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}
This commit is contained in:
@ -898,7 +898,8 @@ void EventLogAnalyzer::CreateFractionLossGraph(Plot* plot) {
|
||||
// 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 @@ void EventLogAnalyzer::CreateTotalBitrateGraph(
|
||||
}
|
||||
|
||||
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 @@ void EventLogAnalyzer::CreateTotalBitrateGraph(
|
||||
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));
|
||||
|
||||
@ -85,7 +85,9 @@ class EventLogAnalyzer {
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@ -90,6 +90,11 @@ DEFINE_string(
|
||||
"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 @@ int main(int argc, char* argv[]) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -75,6 +75,10 @@ void Plot::AppendTimeSeries(TimeSeries&& time_series) {
|
||||
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));
|
||||
|
||||
@ -53,6 +53,29 @@ struct TimeSeries {
|
||||
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 @@ class Plot {
|
||||
// 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 @@ class Plot {
|
||||
std::string yaxis_label_;
|
||||
std::string title_;
|
||||
std::vector<TimeSeries> series_list_;
|
||||
std::vector<IntervalSeries> interval_list_;
|
||||
};
|
||||
|
||||
class PlotCollection {
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace plotting {
|
||||
|
||||
@ -74,6 +76,8 @@ void PythonPlot::Draw() {
|
||||
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 @@ void PythonPlot::Draw() {
|
||||
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 @@ void PythonPlot::Draw() {
|
||||
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 @@ PythonPlotCollection::~PythonPlotCollection() {}
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user