Added -show_detector_state which show the detector state in the total bitrate graph.
BUG=none
Review-Url: https://codereview.webrtc.org/2826313004
Cr-Commit-Position: refs/heads/master@{#19020}
diff --git a/webrtc/rtc_tools/event_log_visualizer/analyzer.cc b/webrtc/rtc_tools/event_log_visualizer/analyzer.cc
index 78993f4..b42f082 100644
--- a/webrtc/rtc_tools/event_log_visualizer/analyzer.cc
+++ b/webrtc/rtc_tools/event_log_visualizer/analyzer.cc
@@ -898,7 +898,8 @@
// Plot the total bandwidth used by all RTP streams.
void EventLogAnalyzer::CreateTotalBitrateGraph(
PacketDirection desired_direction,
- Plot* plot) {
+ Plot* plot,
+ bool show_detector_state) {
struct TimestampSize {
TimestampSize(uint64_t t, size_t s) : timestamp(t), size(s) {}
uint64_t timestamp;
@@ -958,13 +959,46 @@
}
TimeSeries delay_series("Delay-based estimate", LINE_STEP_GRAPH);
+ IntervalSeries overusing_series("Overusing", "#ff8e82",
+ IntervalSeries::kHorizontal);
+ IntervalSeries underusing_series("Underusing", "#5092fc",
+ IntervalSeries::kHorizontal);
+ IntervalSeries normal_series("Normal", "#c4ffc4",
+ IntervalSeries::kHorizontal);
+ IntervalSeries* last_series = &normal_series;
+ double last_detector_switch = 0.0;
+
+ BandwidthUsage last_detector_state = BandwidthUsage::kBwNormal;
+
for (auto& delay_update : bwe_delay_updates_) {
float x =
static_cast<float>(delay_update.timestamp - begin_time_) / 1000000;
float y = static_cast<float>(delay_update.bitrate_bps) / 1000;
+
+ if (last_detector_state != delay_update.detector_state) {
+ last_series->intervals.emplace_back(last_detector_switch, x);
+ last_detector_state = delay_update.detector_state;
+ last_detector_switch = x;
+
+ switch (delay_update.detector_state) {
+ case BandwidthUsage::kBwNormal:
+ last_series = &normal_series;
+ break;
+ case BandwidthUsage::kBwUnderusing:
+ last_series = &underusing_series;
+ break;
+ case BandwidthUsage::kBwOverusing:
+ last_series = &overusing_series;
+ break;
+ }
+ }
+
delay_series.points.emplace_back(x, y);
}
+ RTC_CHECK(last_series);
+ last_series->intervals.emplace_back(last_detector_switch, end_time_);
+
TimeSeries created_series("Probe cluster created.", DOT_GRAPH);
for (auto& cluster : bwe_probe_cluster_created_events_) {
float x = static_cast<float>(cluster.timestamp - begin_time_) / 1000000;
@@ -980,6 +1014,14 @@
result_series.points.emplace_back(x, y);
}
}
+
+ if (show_detector_state) {
+ plot->AppendIntervalSeries(std::move(overusing_series));
+ plot->AppendIntervalSeries(std::move(underusing_series));
+ plot->AppendIntervalSeries(std::move(normal_series));
+ }
+
+ plot->AppendTimeSeries(std::move(bitrate_series));
plot->AppendTimeSeries(std::move(loss_series));
plot->AppendTimeSeries(std::move(delay_series));
plot->AppendTimeSeries(std::move(created_series));
diff --git a/webrtc/rtc_tools/event_log_visualizer/analyzer.h b/webrtc/rtc_tools/event_log_visualizer/analyzer.h
index 0c3fa46..ce4868f 100644
--- a/webrtc/rtc_tools/event_log_visualizer/analyzer.h
+++ b/webrtc/rtc_tools/event_log_visualizer/analyzer.h
@@ -85,7 +85,9 @@
void CreateFractionLossGraph(Plot* plot);
- void CreateTotalBitrateGraph(PacketDirection desired_direction, Plot* plot);
+ void CreateTotalBitrateGraph(PacketDirection desired_direction,
+ Plot* plot,
+ bool show_detector_state = false);
void CreateStreamBitrateGraph(PacketDirection desired_direction, Plot* plot);
diff --git a/webrtc/rtc_tools/event_log_visualizer/main.cc b/webrtc/rtc_tools/event_log_visualizer/main.cc
index 6e78c89..a4490aa 100644
--- a/webrtc/rtc_tools/event_log_visualizer/main.cc
+++ b/webrtc/rtc_tools/event_log_visualizer/main.cc
@@ -90,6 +90,11 @@
"trials are separated by \"/\"");
DEFINE_bool(help, false, "prints this message");
+DEFINE_bool(
+ show_detector_state,
+ false,
+ "Mark the delay based bwe detector state on the total bitrate graph");
+
int main(int argc, char* argv[]) {
std::string program_name = argv[0];
std::string usage =
@@ -178,11 +183,13 @@
if (FLAG_plot_all || FLAG_plot_total_bitrate) {
if (FLAG_incoming) {
analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kIncomingPacket,
- collection->AppendNewPlot());
+ collection->AppendNewPlot(),
+ FLAG_show_detector_state);
}
if (FLAG_outgoing) {
analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kOutgoingPacket,
- collection->AppendNewPlot());
+ collection->AppendNewPlot(),
+ FLAG_show_detector_state);
}
}
diff --git a/webrtc/rtc_tools/event_log_visualizer/plot_base.cc b/webrtc/rtc_tools/event_log_visualizer/plot_base.cc
index 8bf3533..783f2b8 100644
--- a/webrtc/rtc_tools/event_log_visualizer/plot_base.cc
+++ b/webrtc/rtc_tools/event_log_visualizer/plot_base.cc
@@ -75,6 +75,10 @@
series_list_.emplace_back(std::move(time_series));
}
+void Plot::AppendIntervalSeries(IntervalSeries&& interval_series) {
+ interval_list_.emplace_back(std::move(interval_series));
+}
+
void Plot::AppendTimeSeriesIfNotEmpty(TimeSeries&& time_series) {
if (time_series.points.size() > 0) {
series_list_.emplace_back(std::move(time_series));
diff --git a/webrtc/rtc_tools/event_log_visualizer/plot_base.h b/webrtc/rtc_tools/event_log_visualizer/plot_base.h
index bdcea2e..347fca4 100644
--- a/webrtc/rtc_tools/event_log_visualizer/plot_base.h
+++ b/webrtc/rtc_tools/event_log_visualizer/plot_base.h
@@ -53,6 +53,29 @@
std::vector<TimeSeriesPoint> points;
};
+struct Interval {
+ Interval() = default;
+ Interval(double begin, double end) : begin(begin), end(end) {}
+
+ double begin;
+ double end;
+};
+
+struct IntervalSeries {
+ enum Orientation { kHorizontal, kVertical };
+
+ IntervalSeries() = default;
+ IntervalSeries(const std::string& label,
+ const std::string& color,
+ IntervalSeries::Orientation orientation)
+ : label(label), color(color), orientation(orientation) {}
+
+ std::string label;
+ std::string color;
+ Orientation orientation;
+ std::vector<Interval> intervals;
+};
+
// 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.
@@ -109,6 +132,9 @@
// Add a new TimeSeries to the plot.
void AppendTimeSeries(TimeSeries&& time_series);
+ // Add a new IntervalSeries to the plot.
+ void AppendIntervalSeries(IntervalSeries&& interval_series);
+
// Add a new TimeSeries to the plot if the series contains contains data.
// Otherwise, the call has no effect and the timeseries is destroyed.
void AppendTimeSeriesIfNotEmpty(TimeSeries&& time_series);
@@ -122,6 +148,7 @@
std::string yaxis_label_;
std::string title_;
std::vector<TimeSeries> series_list_;
+ std::vector<IntervalSeries> interval_list_;
};
class PlotCollection {
diff --git a/webrtc/rtc_tools/event_log_visualizer/plot_python.cc b/webrtc/rtc_tools/event_log_visualizer/plot_python.cc
index d4ae043..dae2855 100644
--- a/webrtc/rtc_tools/event_log_visualizer/plot_python.cc
+++ b/webrtc/rtc_tools/event_log_visualizer/plot_python.cc
@@ -14,6 +14,8 @@
#include <memory>
+#include "webrtc/rtc_base/checks.h"
+
namespace webrtc {
namespace plotting {
@@ -74,6 +76,8 @@
printf("y%zu = [v for dup in y%zu for v in [dup, dup]]\n", i, i);
printf(
"plt.plot(x%zu[1:], y%zu[:-1], color=rgb_colors[%zu], "
+ "path_effects=[pe.Stroke(linewidth=2, foreground='black'), "
+ "pe.Normal()], "
"label=\'%s\')\n",
i, i, i, series_list_[i].label.c_str());
} else if (series_list_[i].style == DOT_GRAPH) {
@@ -85,6 +89,47 @@
printf("raise Exception(\"Unknown graph type\")\n");
}
}
+
+ // IntervalSeries
+ printf("interval_colors = ['#ff8e82','#5092fc','#c4ffc4']\n");
+ RTC_CHECK_LE(interval_list_.size(), 3);
+ // To get the intervals to show up in the legend we have to created patches
+ // for them.
+ printf("legend_patches = []\n");
+ for (size_t i = 0; i < interval_list_.size(); i++) {
+ // List intervals
+ printf("\n# === IntervalSeries: %s ===\n",
+ interval_list_[i].label.c_str());
+ printf("ival%zu = [", i);
+ if (interval_list_[i].intervals.size() > 0) {
+ printf("(%G, %G)", interval_list_[i].intervals[0].begin,
+ interval_list_[i].intervals[0].end);
+ }
+ for (size_t j = 1; j < interval_list_[i].intervals.size(); j++) {
+ printf(", (%G, %G)", interval_list_[i].intervals[j].begin,
+ interval_list_[i].intervals[j].end);
+ }
+ printf("]\n");
+
+ printf("for i in range(0, %zu):\n", interval_list_[i].intervals.size());
+ if (interval_list_[i].orientation == IntervalSeries::kVertical) {
+ printf(
+ " plt.axhspan(ival%zu[i][0], ival%zu[i][1], "
+ "facecolor=interval_colors[%zu], "
+ "alpha=0.3)\n",
+ i, i, i);
+ } else {
+ printf(
+ " plt.axvspan(ival%zu[i][0], ival%zu[i][1], "
+ "facecolor=interval_colors[%zu], "
+ "alpha=0.3)\n",
+ i, i, i);
+ }
+ printf(
+ "legend_patches.append(mpatches.Patch(ec=\'black\', "
+ "fc=interval_colors[%zu], label='%s'))\n",
+ i, interval_list_[i].label.c_str());
+ }
}
printf("plt.xlim(%f, %f)\n", xaxis_min_, xaxis_max_);
@@ -92,8 +137,12 @@
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");
+ if (!series_list_.empty() || !interval_list_.empty()) {
+ printf("handles, labels = plt.gca().get_legend_handles_labels()\n");
+ printf("for lp in legend_patches:\n");
+ printf(" handles.append(lp)\n");
+ printf(" labels.append(lp.get_label())\n");
+ printf("plt.legend(handles, labels, loc=\'best\', fontsize=\'small\')\n");
}
}
@@ -103,6 +152,8 @@
void PythonPlotCollection::Draw() {
printf("import matplotlib.pyplot as plt\n");
+ printf("import matplotlib.patches as mpatches\n");
+ printf("import matplotlib.patheffects as pe\n");
printf("import colorsys\n");
for (size_t i = 0; i < plots_.size(); i++) {
printf("plt.figure(%zu)\n", i);