Convenience functions to set axis properties in visualization tool.
Also makes the properties protected, as previously requested by Stefan. Review-Url: https://codereview.webrtc.org/2179223003 Cr-Commit-Position: refs/heads/master@{#13593}
This commit is contained in:
@ -32,6 +32,9 @@
|
||||
#include "webrtc/video_receive_stream.h"
|
||||
#include "webrtc/video_send_stream.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace plotting {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string SsrcToString(uint32_t ssrc) {
|
||||
@ -90,17 +93,13 @@ void RegisterHeaderExtensions(
|
||||
}
|
||||
}
|
||||
|
||||
const double kXMargin = 1.02;
|
||||
const double kYMargin = 1.1;
|
||||
const double kDefaultXMin = -1;
|
||||
const double kDefaultYMin = -1;
|
||||
constexpr float kLeftMargin = 0.01f;
|
||||
constexpr float kRightMargin = 0.02f;
|
||||
constexpr float kBottomMargin = 0.02f;
|
||||
constexpr float kTopMargin = 0.05f;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace webrtc {
|
||||
namespace plotting {
|
||||
|
||||
|
||||
bool EventLogAnalyzer::StreamId::operator<(const StreamId& other) const {
|
||||
if (ssrc_ < other.ssrc_) {
|
||||
return true;
|
||||
@ -274,6 +273,7 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
||||
}
|
||||
begin_time_ = first_timestamp;
|
||||
end_time_ = last_timestamp;
|
||||
call_duration_s_ = static_cast<float>(end_time_ - begin_time_) / 1000000;
|
||||
}
|
||||
|
||||
class BitrateObserver : public CongestionController::Observer,
|
||||
@ -311,7 +311,6 @@ void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
|
||||
MediaType media_type;
|
||||
uint8_t header[IP_PACKET_SIZE];
|
||||
size_t header_length, total_length;
|
||||
float max_y = 0;
|
||||
|
||||
for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
|
||||
ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
|
||||
@ -328,7 +327,6 @@ void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
|
||||
uint64_t timestamp = parsed_log_.GetTimestamp(i);
|
||||
float x = static_cast<float>(timestamp - begin_time_) / 1000000;
|
||||
float y = total_length;
|
||||
max_y = std::max(max_y, y);
|
||||
time_series[parsed_header.ssrc].points.push_back(
|
||||
TimeSeriesPoint(x, y));
|
||||
}
|
||||
@ -340,19 +338,16 @@ void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
|
||||
for (auto& kv : time_series) {
|
||||
kv.second.label = SsrcToString(kv.first);
|
||||
kv.second.style = BAR_GRAPH;
|
||||
plot->series.push_back(std::move(kv.second));
|
||||
plot->series_list_.push_back(std::move(kv.second));
|
||||
}
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = kDefaultYMin;
|
||||
plot->yaxis_max = max_y * kYMargin;
|
||||
plot->yaxis_label = "Packet size (bytes)";
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 1, "Packet size (bytes)", kBottomMargin,
|
||||
kTopMargin);
|
||||
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
|
||||
plot->title = "Incoming RTP packets";
|
||||
plot->SetTitle("Incoming RTP packets");
|
||||
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
|
||||
plot->title = "Outgoing RTP packets";
|
||||
plot->SetTitle("Outgoing RTP packets");
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,7 +357,6 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
|
||||
std::map<uint32_t, uint64_t> last_playout;
|
||||
|
||||
uint32_t ssrc;
|
||||
float max_y = 0;
|
||||
|
||||
for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
|
||||
ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
|
||||
@ -377,7 +371,6 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
|
||||
// Generate a point, but place it on the x-axis.
|
||||
y = 0;
|
||||
}
|
||||
max_y = std::max(max_y, y);
|
||||
time_series[ssrc].points.push_back(TimeSeriesPoint(x, y));
|
||||
last_playout[ssrc] = timestamp;
|
||||
}
|
||||
@ -388,16 +381,13 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
|
||||
for (auto& kv : time_series) {
|
||||
kv.second.label = SsrcToString(kv.first);
|
||||
kv.second.style = BAR_GRAPH;
|
||||
plot->series.push_back(std::move(kv.second));
|
||||
plot->series_list_.push_back(std::move(kv.second));
|
||||
}
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = kDefaultYMin;
|
||||
plot->yaxis_max = max_y * kYMargin;
|
||||
plot->yaxis_label = "Time since last playout (ms)";
|
||||
plot->title = "Audio playout";
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 1, "Time since last playout (ms)", kBottomMargin,
|
||||
kTopMargin);
|
||||
plot->SetTitle("Audio playout");
|
||||
}
|
||||
|
||||
// For each SSRC, plot the time between the consecutive playouts.
|
||||
@ -410,9 +400,6 @@ void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
|
||||
uint8_t header[IP_PACKET_SIZE];
|
||||
size_t header_length, total_length;
|
||||
|
||||
int max_y = 1;
|
||||
int min_y = 0;
|
||||
|
||||
for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
|
||||
ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
|
||||
if (event_type == ParsedRtcEventLog::RTP_EVENT) {
|
||||
@ -434,8 +421,6 @@ void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
|
||||
// Generate a point, but place it on the x-axis.
|
||||
y = 0;
|
||||
}
|
||||
max_y = std::max(max_y, y);
|
||||
min_y = std::min(min_y, y);
|
||||
time_series[parsed_header.ssrc].points.push_back(
|
||||
TimeSeriesPoint(x, y));
|
||||
last_seqno[parsed_header.ssrc] = parsed_header.sequenceNumber;
|
||||
@ -448,22 +433,16 @@ void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
|
||||
for (auto& kv : time_series) {
|
||||
kv.second.label = SsrcToString(kv.first);
|
||||
kv.second.style = BAR_GRAPH;
|
||||
plot->series.push_back(std::move(kv.second));
|
||||
plot->series_list_.push_back(std::move(kv.second));
|
||||
}
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_label = "Difference since last packet";
|
||||
plot->title = "Sequence number";
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 1, "Difference since last packet", kBottomMargin,
|
||||
kTopMargin);
|
||||
plot->SetTitle("Sequence number");
|
||||
}
|
||||
|
||||
void EventLogAnalyzer::CreateDelayChangeGraph(Plot* plot) {
|
||||
double max_y = 10;
|
||||
double min_y = 0;
|
||||
|
||||
for (auto& kv : rtp_packets_) {
|
||||
StreamId stream_id = kv.first;
|
||||
// Filter on direction and SSRC.
|
||||
@ -498,28 +477,20 @@ void EventLogAnalyzer::CreateDelayChangeGraph(Plot* plot) {
|
||||
// Generate a point, but place it on the x-axis.
|
||||
y = 0;
|
||||
}
|
||||
max_y = std::max(max_y, y);
|
||||
min_y = std::min(min_y, y);
|
||||
time_series.points.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
// Add the data set to the plot.
|
||||
plot->series.push_back(std::move(time_series));
|
||||
plot->series_list_.push_back(std::move(time_series));
|
||||
}
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_label = "Latency change (ms)";
|
||||
plot->title = "Network latency change between consecutive packets";
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin,
|
||||
kTopMargin);
|
||||
plot->SetTitle("Network latency change between consecutive packets");
|
||||
}
|
||||
|
||||
void EventLogAnalyzer::CreateAccumulatedDelayChangeGraph(Plot* plot) {
|
||||
double max_y = 10;
|
||||
double min_y = 0;
|
||||
|
||||
for (auto& kv : rtp_packets_) {
|
||||
StreamId stream_id = kv.first;
|
||||
// Filter on direction and SSRC.
|
||||
@ -554,22 +525,17 @@ void EventLogAnalyzer::CreateAccumulatedDelayChangeGraph(Plot* plot) {
|
||||
// Generate a point, but place it on the x-axis.
|
||||
accumulated_delay_ms = 0;
|
||||
}
|
||||
max_y = std::max(max_y, accumulated_delay_ms);
|
||||
min_y = std::min(min_y, accumulated_delay_ms);
|
||||
time_series.points.emplace_back(x, accumulated_delay_ms);
|
||||
}
|
||||
}
|
||||
// Add the data set to the plot.
|
||||
plot->series.push_back(std::move(time_series));
|
||||
plot->series_list_.push_back(std::move(time_series));
|
||||
}
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_label = "Latency change (ms)";
|
||||
plot->title = "Accumulated network latency change";
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin,
|
||||
kTopMargin);
|
||||
plot->SetTitle("Accumulated network latency change");
|
||||
}
|
||||
|
||||
// Plot the total bandwidth used by all RTP streams.
|
||||
@ -602,10 +568,9 @@ void EventLogAnalyzer::CreateTotalBitrateGraph(
|
||||
size_t window_index_begin = 0;
|
||||
size_t window_index_end = 0;
|
||||
size_t bytes_in_window = 0;
|
||||
float max_y = 0;
|
||||
|
||||
// Calculate a moving average of the bitrate and store in a TimeSeries.
|
||||
plot->series.push_back(TimeSeries());
|
||||
plot->series_list_.push_back(TimeSeries());
|
||||
for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) {
|
||||
while (window_index_end < packets.size() &&
|
||||
packets[window_index_end].timestamp < time) {
|
||||
@ -622,42 +587,36 @@ void EventLogAnalyzer::CreateTotalBitrateGraph(
|
||||
static_cast<float>(window_duration_) / 1000000;
|
||||
float x = static_cast<float>(time - begin_time_) / 1000000;
|
||||
float y = bytes_in_window * 8 / window_duration_in_seconds / 1000;
|
||||
max_y = std::max(max_y, y);
|
||||
plot->series.back().points.push_back(TimeSeriesPoint(x, y));
|
||||
plot->series_list_.back().points.push_back(TimeSeriesPoint(x, y));
|
||||
}
|
||||
|
||||
// Set labels.
|
||||
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
|
||||
plot->series.back().label = "Incoming bitrate";
|
||||
plot->series_list_.back().label = "Incoming bitrate";
|
||||
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
|
||||
plot->series.back().label = "Outgoing bitrate";
|
||||
plot->series_list_.back().label = "Outgoing bitrate";
|
||||
}
|
||||
plot->series.back().style = LINE_GRAPH;
|
||||
plot->series_list_.back().style = LINE_GRAPH;
|
||||
|
||||
// Overlay the send-side bandwidth estimate over the outgoing bitrate.
|
||||
if (desired_direction == kOutgoingPacket) {
|
||||
plot->series.push_back(TimeSeries());
|
||||
plot->series_list_.push_back(TimeSeries());
|
||||
for (auto& bwe_update : bwe_loss_updates_) {
|
||||
float x =
|
||||
static_cast<float>(bwe_update.timestamp - begin_time_) / 1000000;
|
||||
float y = static_cast<float>(bwe_update.new_bitrate) / 1000;
|
||||
max_y = std::max(max_y, y);
|
||||
plot->series.back().points.emplace_back(x, y);
|
||||
plot->series_list_.back().points.emplace_back(x, y);
|
||||
}
|
||||
plot->series.back().label = "Loss-based estimate";
|
||||
plot->series.back().style = LINE_GRAPH;
|
||||
plot->series_list_.back().label = "Loss-based estimate";
|
||||
plot->series_list_.back().style = LINE_GRAPH;
|
||||
}
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = kDefaultYMin;
|
||||
plot->yaxis_max = max_y * kYMargin;
|
||||
plot->yaxis_label = "Bitrate (kbps)";
|
||||
plot->series_list_.back().style = LINE_GRAPH;
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
|
||||
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
|
||||
plot->title = "Incoming RTP bitrate";
|
||||
plot->SetTitle("Incoming RTP bitrate");
|
||||
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
|
||||
plot->title = "Outgoing RTP bitrate";
|
||||
plot->SetTitle("Outgoing RTP bitrate");
|
||||
}
|
||||
}
|
||||
|
||||
@ -698,15 +657,13 @@ void EventLogAnalyzer::CreateStreamBitrateGraph(
|
||||
}
|
||||
}
|
||||
|
||||
float max_y = 0;
|
||||
|
||||
for (auto& kv : packets) {
|
||||
size_t window_index_begin = 0;
|
||||
size_t window_index_end = 0;
|
||||
size_t bytes_in_window = 0;
|
||||
|
||||
// Calculate a moving average of the bitrate and store in a TimeSeries.
|
||||
plot->series.push_back(TimeSeries());
|
||||
plot->series_list_.push_back(TimeSeries());
|
||||
for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) {
|
||||
while (window_index_end < kv.second.size() &&
|
||||
kv.second[window_index_end].timestamp < time) {
|
||||
@ -724,25 +681,20 @@ void EventLogAnalyzer::CreateStreamBitrateGraph(
|
||||
static_cast<float>(window_duration_) / 1000000;
|
||||
float x = static_cast<float>(time - begin_time_) / 1000000;
|
||||
float y = bytes_in_window * 8 / window_duration_in_seconds / 1000;
|
||||
max_y = std::max(max_y, y);
|
||||
plot->series.back().points.push_back(TimeSeriesPoint(x, y));
|
||||
plot->series_list_.back().points.push_back(TimeSeriesPoint(x, y));
|
||||
}
|
||||
|
||||
// Set labels.
|
||||
plot->series.back().label = SsrcToString(kv.first);
|
||||
plot->series.back().style = LINE_GRAPH;
|
||||
plot->series_list_.back().label = SsrcToString(kv.first);
|
||||
plot->series_list_.back().style = LINE_GRAPH;
|
||||
}
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = kDefaultYMin;
|
||||
plot->yaxis_max = max_y * kYMargin;
|
||||
plot->yaxis_label = "Bitrate (kbps)";
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
|
||||
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
|
||||
plot->title = "Incoming bitrate per stream";
|
||||
plot->SetTitle("Incoming bitrate per stream");
|
||||
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
|
||||
plot->title = "Outgoing bitrate per stream";
|
||||
plot->SetTitle("Outgoing bitrate per stream");
|
||||
}
|
||||
}
|
||||
|
||||
@ -776,8 +728,6 @@ void EventLogAnalyzer::CreateBweGraph(Plot* plot) {
|
||||
TimeSeries time_series;
|
||||
time_series.label = "BWE";
|
||||
time_series.style = LINE_DOT_GRAPH;
|
||||
uint32_t max_y = 10;
|
||||
uint32_t min_y = 0;
|
||||
|
||||
auto rtp_iterator = outgoing_rtp.begin();
|
||||
auto rtcp_iterator = incoming_rtcp.begin();
|
||||
@ -834,8 +784,6 @@ void EventLogAnalyzer::CreateBweGraph(Plot* plot) {
|
||||
cc.Process();
|
||||
if (observer.GetAndResetBitrateUpdated()) {
|
||||
uint32_t y = observer.last_bitrate_bps() / 1000;
|
||||
max_y = std::max(max_y, y);
|
||||
min_y = std::min(min_y, y);
|
||||
float x = static_cast<float>(clock.TimeInMicroseconds() - begin_time_) /
|
||||
1000000;
|
||||
time_series.points.emplace_back(x, y);
|
||||
@ -843,15 +791,11 @@ void EventLogAnalyzer::CreateBweGraph(Plot* plot) {
|
||||
time_us = std::min({NextRtpTime(), NextRtcpTime(), NextProcessTime()});
|
||||
}
|
||||
// Add the data set to the plot.
|
||||
plot->series.push_back(std::move(time_series));
|
||||
plot->series_list_.push_back(std::move(time_series));
|
||||
|
||||
plot->xaxis_min = kDefaultXMin;
|
||||
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
|
||||
plot->xaxis_label = "Time (s)";
|
||||
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
|
||||
plot->yaxis_label = "Bitrate (kbps)";
|
||||
plot->title = "BWE";
|
||||
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
|
||||
plot->SetSuggestedYAxis(0, 10, "Bitrate (kbps)", kBottomMargin, kTopMargin);
|
||||
plot->SetTitle("Simulated BWE behavior");
|
||||
}
|
||||
|
||||
} // namespace plotting
|
||||
|
||||
@ -115,6 +115,9 @@ class EventLogAnalyzer {
|
||||
// First and last events of the log.
|
||||
uint64_t begin_time_;
|
||||
uint64_t end_time_;
|
||||
|
||||
// Duration (in seconds) of log file.
|
||||
float call_duration_s_;
|
||||
};
|
||||
|
||||
} // namespace plotting
|
||||
|
||||
@ -82,44 +82,44 @@ int main(int argc, char* argv[]) {
|
||||
if (FLAGS_plot_all || FLAGS_plot_packets) {
|
||||
if (FLAGS_incoming) {
|
||||
analyzer.CreatePacketGraph(webrtc::PacketDirection::kIncomingPacket,
|
||||
collection->append_new_plot());
|
||||
collection->AppendNewPlot());
|
||||
}
|
||||
if (FLAGS_outgoing) {
|
||||
analyzer.CreatePacketGraph(webrtc::PacketDirection::kOutgoingPacket,
|
||||
collection->append_new_plot());
|
||||
collection->AppendNewPlot());
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_plot_all || FLAGS_plot_audio_playout) {
|
||||
analyzer.CreatePlayoutGraph(collection->append_new_plot());
|
||||
analyzer.CreatePlayoutGraph(collection->AppendNewPlot());
|
||||
}
|
||||
|
||||
if (FLAGS_plot_all || FLAGS_plot_sequence_number) {
|
||||
if (FLAGS_incoming) {
|
||||
analyzer.CreateSequenceNumberGraph(collection->append_new_plot());
|
||||
analyzer.CreateSequenceNumberGraph(collection->AppendNewPlot());
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_plot_all || FLAGS_plot_delay_change) {
|
||||
if (FLAGS_incoming) {
|
||||
analyzer.CreateDelayChangeGraph(collection->append_new_plot());
|
||||
analyzer.CreateDelayChangeGraph(collection->AppendNewPlot());
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_plot_all || FLAGS_plot_accumulated_delay_change) {
|
||||
if (FLAGS_incoming) {
|
||||
analyzer.CreateAccumulatedDelayChangeGraph(collection->append_new_plot());
|
||||
analyzer.CreateAccumulatedDelayChangeGraph(collection->AppendNewPlot());
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_plot_all || FLAGS_plot_total_bitrate) {
|
||||
if (FLAGS_incoming) {
|
||||
analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kIncomingPacket,
|
||||
collection->append_new_plot());
|
||||
collection->AppendNewPlot());
|
||||
}
|
||||
if (FLAGS_outgoing) {
|
||||
analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kOutgoingPacket,
|
||||
collection->append_new_plot());
|
||||
collection->AppendNewPlot());
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,20 +127,20 @@ int main(int argc, char* argv[]) {
|
||||
if (FLAGS_incoming) {
|
||||
analyzer.CreateStreamBitrateGraph(
|
||||
webrtc::PacketDirection::kIncomingPacket,
|
||||
collection->append_new_plot());
|
||||
collection->AppendNewPlot());
|
||||
}
|
||||
if (FLAGS_outgoing) {
|
||||
analyzer.CreateStreamBitrateGraph(
|
||||
webrtc::PacketDirection::kOutgoingPacket,
|
||||
collection->append_new_plot());
|
||||
collection->AppendNewPlot());
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_plot_all || FLAGS_plot_bwe) {
|
||||
analyzer.CreateBweGraph(collection->append_new_plot());
|
||||
analyzer.CreateBweGraph(collection->AppendNewPlot());
|
||||
}
|
||||
|
||||
collection->draw();
|
||||
collection->Draw();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
75
webrtc/tools/event_log_visualizer/plot_base.cc
Normal file
75
webrtc/tools/event_log_visualizer/plot_base.cc
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/tools/event_log_visualizer/plot_base.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace plotting {
|
||||
|
||||
void Plot::SetXAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float left_margin,
|
||||
float right_margin) {
|
||||
RTC_DCHECK_LE(min_value, max_value);
|
||||
xaxis_min_ = min_value - left_margin * (max_value - min_value);
|
||||
xaxis_max_ = max_value + right_margin * (max_value - min_value);
|
||||
xaxis_label_ = label;
|
||||
}
|
||||
|
||||
void Plot::SetSuggestedXAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float left_margin,
|
||||
float right_margin) {
|
||||
for (const auto& series : series_list_) {
|
||||
for (const auto& point : series.points) {
|
||||
min_value = std::min(min_value, point.x);
|
||||
max_value = std::max(max_value, point.x);
|
||||
}
|
||||
}
|
||||
SetXAxis(min_value, max_value, label, left_margin, right_margin);
|
||||
}
|
||||
|
||||
void Plot::SetYAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float bottom_margin,
|
||||
float top_margin) {
|
||||
RTC_DCHECK_LE(min_value, max_value);
|
||||
yaxis_min_ = min_value - bottom_margin * (max_value - min_value);
|
||||
yaxis_max_ = max_value + top_margin * (max_value - min_value);
|
||||
yaxis_label_ = label;
|
||||
}
|
||||
|
||||
void Plot::SetSuggestedYAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float bottom_margin,
|
||||
float top_margin) {
|
||||
for (const auto& series : series_list_) {
|
||||
for (const auto& point : series.points) {
|
||||
min_value = std::min(min_value, point.y);
|
||||
max_value = std::max(max_value, point.y);
|
||||
}
|
||||
}
|
||||
SetYAxis(min_value, max_value, label, bottom_margin, top_margin);
|
||||
}
|
||||
|
||||
void Plot::SetTitle(std::string title) {
|
||||
title_ = title;
|
||||
}
|
||||
|
||||
} // namespace plotting
|
||||
} // namespace webrtc
|
||||
@ -44,32 +44,79 @@ struct TimeSeries {
|
||||
std::vector<TimeSeriesPoint> points;
|
||||
};
|
||||
|
||||
// This is basically a struct that represents of a general graph, with axes,
|
||||
// title and one or more data series. We make it a class only to document that
|
||||
// it also specifies an interface for the draw()ing objects.
|
||||
// A container that represents a general graph, with axes, title and one or
|
||||
// more data series. A subclass should define the output format by overriding
|
||||
// the Draw() method.
|
||||
class Plot {
|
||||
public:
|
||||
virtual ~Plot() {}
|
||||
virtual void draw() = 0;
|
||||
|
||||
float xaxis_min;
|
||||
float xaxis_max;
|
||||
std::string xaxis_label;
|
||||
float yaxis_min;
|
||||
float yaxis_max;
|
||||
std::string yaxis_label;
|
||||
std::vector<TimeSeries> series;
|
||||
std::string title;
|
||||
// Overloaded to draw the plot.
|
||||
virtual void Draw() = 0;
|
||||
|
||||
// Sets the lower x-axis limit to min_value (if left_margin == 0).
|
||||
// Sets the upper x-axis limit to max_value (if right_margin == 0).
|
||||
// The margins are measured as fractions of the interval
|
||||
// (max_value - min_value) and are added to either side of the plot.
|
||||
void SetXAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float left_margin = 0,
|
||||
float right_margin = 0);
|
||||
|
||||
// Sets the lower and upper x-axis limits based on min_value and max_value,
|
||||
// but modified such that all points in the data series can be represented
|
||||
// on the x-axis. The margins are measured as fractions of the range of
|
||||
// x-values and are added to either side of the plot.
|
||||
void SetSuggestedXAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float left_margin = 0,
|
||||
float right_margin = 0);
|
||||
|
||||
// Sets the lower y-axis limit to min_value (if bottom_margin == 0).
|
||||
// Sets the upper y-axis limit to max_value (if top_margin == 0).
|
||||
// The margins are measured as fractions of the interval
|
||||
// (max_value - min_value) and are added to either side of the plot.
|
||||
void SetYAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float bottom_margin = 0,
|
||||
float top_margin = 0);
|
||||
|
||||
// Sets the lower and upper y-axis limits based on min_value and max_value,
|
||||
// but modified such that all points in the data series can be represented
|
||||
// on the y-axis. The margins are measured as fractions of the range of
|
||||
// y-values and are added to either side of the plot.
|
||||
void SetSuggestedYAxis(float min_value,
|
||||
float max_value,
|
||||
std::string label,
|
||||
float bottom_margin = 0,
|
||||
float top_margin = 0);
|
||||
|
||||
// Sets the title of the plot.
|
||||
void SetTitle(std::string title);
|
||||
|
||||
std::vector<TimeSeries> series_list_;
|
||||
|
||||
protected:
|
||||
float xaxis_min_;
|
||||
float xaxis_max_;
|
||||
std::string xaxis_label_;
|
||||
float yaxis_min_;
|
||||
float yaxis_max_;
|
||||
std::string yaxis_label_;
|
||||
std::string title_;
|
||||
};
|
||||
|
||||
class PlotCollection {
|
||||
public:
|
||||
virtual ~PlotCollection() {}
|
||||
virtual void draw() = 0;
|
||||
virtual Plot* append_new_plot() = 0;
|
||||
virtual void Draw() = 0;
|
||||
virtual Plot* AppendNewPlot() = 0;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<Plot> > plots;
|
||||
std::vector<std::unique_ptr<Plot> > plots_;
|
||||
};
|
||||
|
||||
} // namespace plotting
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "webrtc/tools/event_log_visualizer/plot_python.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace webrtc {
|
||||
@ -20,62 +21,62 @@ PythonPlot::PythonPlot() {}
|
||||
|
||||
PythonPlot::~PythonPlot() {}
|
||||
|
||||
void PythonPlot::draw() {
|
||||
void PythonPlot::Draw() {
|
||||
// Write python commands to stdout. Intended program usage is
|
||||
// ./event_log_visualizer event_log160330.dump | python
|
||||
|
||||
if (!series.empty()) {
|
||||
printf("color_count = %zu\n", series.size());
|
||||
if (!series_list_.empty()) {
|
||||
printf("color_count = %zu\n", series_list_.size());
|
||||
printf(
|
||||
"hls_colors = [(i*1.0/color_count, 0.25+i*0.5/color_count, 0.8) for i "
|
||||
"in range(color_count)]\n");
|
||||
printf("rgb_colors = [colorsys.hls_to_rgb(*hls) for hls in hls_colors]\n");
|
||||
|
||||
for (size_t i = 0; i < series.size(); i++) {
|
||||
for (size_t i = 0; i < series_list_.size(); i++) {
|
||||
// List x coordinates
|
||||
printf("x%zu = [", i);
|
||||
if (series[i].points.size() > 0)
|
||||
printf("%G", series[i].points[0].x);
|
||||
for (size_t j = 1; j < series[i].points.size(); j++)
|
||||
printf(", %G", series[i].points[j].x);
|
||||
if (series_list_[i].points.size() > 0)
|
||||
printf("%G", series_list_[i].points[0].x);
|
||||
for (size_t j = 1; j < series_list_[i].points.size(); j++)
|
||||
printf(", %G", series_list_[i].points[j].x);
|
||||
printf("]\n");
|
||||
|
||||
// List y coordinates
|
||||
printf("y%zu = [", i);
|
||||
if (series[i].points.size() > 0)
|
||||
printf("%G", series[i].points[0].y);
|
||||
for (size_t j = 1; j < series[i].points.size(); j++)
|
||||
printf(", %G", series[i].points[j].y);
|
||||
if (series_list_[i].points.size() > 0)
|
||||
printf("%G", series_list_[i].points[0].y);
|
||||
for (size_t j = 1; j < series_list_[i].points.size(); j++)
|
||||
printf(", %G", series_list_[i].points[j].y);
|
||||
printf("]\n");
|
||||
|
||||
if (series[i].style == BAR_GRAPH) {
|
||||
if (series_list_[i].style == BAR_GRAPH) {
|
||||
// There is a plt.bar function that draws bar plots,
|
||||
// but it is *way* too slow to be useful.
|
||||
printf(
|
||||
"plt.vlines(x%zu, map(lambda t: min(t,0), y%zu), map(lambda t: "
|
||||
"max(t,0), y%zu), color=rgb_colors[%zu], "
|
||||
"label=\'%s\')\n",
|
||||
i, i, i, i, series[i].label.c_str());
|
||||
} else if (series[i].style == LINE_GRAPH) {
|
||||
i, i, i, i, series_list_[i].label.c_str());
|
||||
} else if (series_list_[i].style == LINE_GRAPH) {
|
||||
printf("plt.plot(x%zu, y%zu, color=rgb_colors[%zu], label=\'%s\')\n", i,
|
||||
i, i, series[i].label.c_str());
|
||||
} else if (series[i].style == LINE_DOT_GRAPH) {
|
||||
i, i, series_list_[i].label.c_str());
|
||||
} else if (series_list_[i].style == LINE_DOT_GRAPH) {
|
||||
printf(
|
||||
"plt.plot(x%zu, y%zu, color=rgb_colors[%zu], label=\'%s\', "
|
||||
"marker='.')\n",
|
||||
i, i, i, series[i].label.c_str());
|
||||
i, i, i, series_list_[i].label.c_str());
|
||||
} else {
|
||||
printf("raise Exception(\"Unknown graph type\")\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("plt.xlim(%f, %f)\n", xaxis_min, xaxis_max);
|
||||
printf("plt.ylim(%f, %f)\n", yaxis_min, yaxis_max);
|
||||
printf("plt.xlabel(\'%s\')\n", xaxis_label.c_str());
|
||||
printf("plt.ylabel(\'%s\')\n", yaxis_label.c_str());
|
||||
printf("plt.title(\'%s\')\n", title.c_str());
|
||||
if (!series.empty()) {
|
||||
printf("plt.xlim(%f, %f)\n", xaxis_min_, xaxis_max_);
|
||||
printf("plt.ylim(%f, %f)\n", yaxis_min_, yaxis_max_);
|
||||
printf("plt.xlabel(\'%s\')\n", xaxis_label_.c_str());
|
||||
printf("plt.ylabel(\'%s\')\n", yaxis_label_.c_str());
|
||||
printf("plt.title(\'%s\')\n", title_.c_str());
|
||||
if (!series_list_.empty()) {
|
||||
printf("plt.legend(loc=\'best\', fontsize=\'small\')\n");
|
||||
}
|
||||
}
|
||||
@ -84,19 +85,19 @@ PythonPlotCollection::PythonPlotCollection() {}
|
||||
|
||||
PythonPlotCollection::~PythonPlotCollection() {}
|
||||
|
||||
void PythonPlotCollection::draw() {
|
||||
void PythonPlotCollection::Draw() {
|
||||
printf("import matplotlib.pyplot as plt\n");
|
||||
printf("import colorsys\n");
|
||||
for (size_t i = 0; i < plots.size(); i++) {
|
||||
for (size_t i = 0; i < plots_.size(); i++) {
|
||||
printf("plt.figure(%zu)\n", i);
|
||||
plots[i]->draw();
|
||||
plots_[i]->Draw();
|
||||
}
|
||||
printf("plt.show()\n");
|
||||
}
|
||||
|
||||
Plot* PythonPlotCollection::append_new_plot() {
|
||||
Plot* PythonPlotCollection::AppendNewPlot() {
|
||||
Plot* plot = new PythonPlot();
|
||||
plots.push_back(std::unique_ptr<Plot>(plot));
|
||||
plots_.push_back(std::unique_ptr<Plot>(plot));
|
||||
return plot;
|
||||
}
|
||||
|
||||
|
||||
@ -19,15 +19,15 @@ class PythonPlot final : public Plot {
|
||||
public:
|
||||
PythonPlot();
|
||||
~PythonPlot() override;
|
||||
void draw() override;
|
||||
void Draw() override;
|
||||
};
|
||||
|
||||
class PythonPlotCollection final : public PlotCollection {
|
||||
public:
|
||||
PythonPlotCollection();
|
||||
~PythonPlotCollection() override;
|
||||
void draw() override;
|
||||
Plot* append_new_plot() override;
|
||||
void Draw() override;
|
||||
Plot* AppendNewPlot() override;
|
||||
};
|
||||
|
||||
} // namespace plotting
|
||||
|
||||
Reference in New Issue
Block a user