Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(745)

Side by Side Diff: webrtc/modules/remote_bitrate_estimator/test/metric_recorder.cc

Issue 1202253003: More Simulation Framework features (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Comments addressed Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/modules/remote_bitrate_estimator/test/metric_recorder.h"
12
13 #include <algorithm>
14
15 namespace webrtc {
16 namespace testing {
17 namespace bwe {
18
19 namespace {
20
21 template <typename T>
22 T Sum(const std::vector<T>& input) {
23 T total = 0;
24 for (auto it = input.begin(); it != input.end(); ++it) {
25 total += *it;
26 }
27 return total;
28 }
29
30 template <typename T>
31 double Average(const std::vector<T>& array, size_t size) {
32 return static_cast<double>(Sum(array)) / size;
33 }
34
35 template <typename T>
36 std::vector<T> Abs(const std::vector<T>& input) {
37 std::vector<T> output;
38 for (auto it = input.begin(); it != input.end(); ++it) {
39 output.push_back(std::abs(*it));
40 }
41 return output;
42 }
43
44 template <typename T>
45 std::vector<double> Pow(const std::vector<T>& input, double p) {
46 std::vector<double> output;
47 for (auto it = input.begin(); it != input.end(); ++it) {
48 output.push_back(pow(static_cast<double>(*it), p));
49 }
50 return output;
51 }
52
53 template <typename T>
54 double StandardDeviation(const std::vector<T>& array, size_t size) {
55 double mean = Average(array, size);
56 std::vector<double> square_values = Pow(array, 2.0);
57 double var = Average(square_values, size) - mean * mean;
58 return sqrt(var);
59 }
60
61 // Holder mean, Manhattan distance for p=1, EuclidianNorm/sqrt(n) for p=2.
62 template <typename T>
63 double NormLp(const std::vector<T>& array, size_t size, double p) {
64 std::vector<T> abs_values = Abs(array);
65 std::vector<double> pow_values = Pow(abs_values, p);
66 return pow(Sum(pow_values) / size, 1.0 / p);
67 }
68
69 template <typename T>
70 std::vector<T> PositiveFilter(const std::vector<T>& input) {
71 std::vector<T> output(input);
72 for (auto it = output.begin(); it != output.end(); ++it) {
stefan-webrtc 2015/07/02 11:03:41 Can't you do this? for (T val : output) val = va
magalhaesc 2015/07/02 17:06:18 Done.
73 (*it) = (*it) > 0 ? (*it) : 0;
74 }
75 return output;
76 }
77
78 template <typename T>
79 std::vector<T> NegativeFilter(const std::vector<T>& input) {
80 std::vector<T> output(input);
81 for (auto it = output.begin(); it != output.end(); ++it) {
82 (*it) = (*it) < 0 ? -(*it) : 0;
83 }
84 return output;
85 }
86 } // namespace
87
88 MetricRecorder::MetricRecorder(const std::string algorithm_name,
89 int flow_id,
90 PacketSender* packet_sender,
91 ChokeFilter* choke_filter)
92 : algorithm_name_(algorithm_name),
93 flow_id_(flow_id),
94 packet_sender_(packet_sender),
95 choke_filter_(choke_filter),
96 now_ms_(0),
97 delays_ms_(),
98 throughput_bytes_(),
99 weighted_estimate_error_(),
100 last_unweighted_estimate_error_(0),
101 optimal_throughput_bits_(0),
102 last_available_bitrate_per_flow_kbps_(0),
103 start_computing_metrics_ms_(0),
104 started_computing_metrics_(false) {
105 std::fill(last_plot_ms_, last_plot_ms_ + kNumMetrics, 0);
106 std::fill(plot_, plot_ + kNumMetrics, true);
107 plot_[kObjective] = false;
108 plot_[kAvailablePerFlow] = false;
109 }
110
111 void MetricRecorder::PlotLine(int windows_id,
112 const std::string& prefix,
113 int64_t x,
114 int64_t y) {
115 BWE_TEST_LOGGING_PLOT_WITH_NAME(windows_id, prefix, x, y, algorithm_name_);
116 }
117
118 void MetricRecorder::PlotThroughput(const std::string& prefix,
119 int64_t time_ms,
120 int64_t bitrate_kbps) {
121 if (!plot_[kThroughput])
122 return;
123 static const int kThroughputPlotIntervalMs = 100;
124 if (time_ms - last_plot_ms_[kThroughput] > kThroughputPlotIntervalMs) {
125 PlotLine(0, prefix, time_ms, bitrate_kbps);
126 last_plot_ms_[kThroughput] = time_ms;
127 }
128 }
129
130 void MetricRecorder::PlotDelay(const std::string& prefix,
131 int64_t time_ms,
132 int64_t delay_ms) {
133 if (!plot_[kDelay])
134 return;
135 static const int kDelayPlotIntervalMs = 100;
136 if (time_ms - last_plot_ms_[kDelay] > kDelayPlotIntervalMs) {
137 PlotLine(1, prefix, time_ms, delay_ms);
138 last_plot_ms_[kDelay] = time_ms;
139 }
140 }
141
142 void MetricRecorder::PlotLoss(const std::string& prefix,
143 int64_t time_ms,
144 double loss) {
145 if (!plot_[kLoss])
146 return;
147 static const int kPacketLossPlotIntervalMs = 500;
148 if (time_ms - last_plot_ms_[kLoss] > kPacketLossPlotIntervalMs) {
149 PlotLine(2, prefix, time_ms, loss);
150 last_plot_ms_[kLoss] = time_ms;
151 }
152 }
153
154 void MetricRecorder::PlotObjective(const std::string& prefix, int64_t time_ms) {
155 if (!plot_[kObjective])
156 return;
157 static const int kMetricPlotIntervalMs = 1000;
158 if (time_ms - last_plot_ms_[kObjective] > kMetricPlotIntervalMs) {
159 PlotLine(3, prefix, time_ms, ObjectiveFunction());
160 last_plot_ms_[kObjective] = time_ms;
161 }
162 }
163
164 void MetricRecorder::PlotTotalAvailableCapacity(const std::string& prefix,
165 int64_t time_ms) {
166 if (!plot_[kTotalAvailable])
167 return;
168 static const int kCapacityPlotIntervalMs = 1000;
169 if (time_ms - last_plot_ms_[kTotalAvailable] > kCapacityPlotIntervalMs) {
170 BWE_TEST_LOGGING_PLOT_WITH_NAME(0, prefix, time_ms, GetTotalAvailableKbps(),
171 "Available");
172 last_plot_ms_[kTotalAvailable] = time_ms;
173 }
174 }
175
176 void MetricRecorder::PlotAvailableCapacityPerFlow(const std::string& prefix,
177 int64_t time_ms) {
178 if (!plot_[kAvailablePerFlow])
179 return;
180 static const int kCapacityPlotIntervalMs = 1000;
181 if (time_ms - last_plot_ms_[kAvailablePerFlow] > kCapacityPlotIntervalMs) {
182 BWE_TEST_LOGGING_PLOT_WITH_NAME(
183 0, prefix, time_ms, GetAvailablePerFlowKbps(), "Available_per_flow");
184 last_plot_ms_[kAvailablePerFlow] = time_ms;
185 }
186 }
187
188 uint32_t MetricRecorder::GetTotalAvailableKbps() {
189 return choke_filter_->TotalAvailableKbps();
190 }
191
192 uint32_t MetricRecorder::GetAvailablePerFlowKbps() {
193 return choke_filter_->AvailablePerFlowKbps(flow_id_);
194 }
195
196 uint32_t MetricRecorder::GetSendingEstimateKbps() {
197 return packet_sender_->TargetBitrateKbps();
198 }
199
200 void MetricRecorder::Update(int64_t time_ms) {
201 now_ms_ = std::max(now_ms_, time_ms);
202 last_available_bitrate_per_flow_kbps_ = GetAvailablePerFlowKbps();
203 }
204
205 void MetricRecorder::PushDelayMs(int64_t delay_ms, int64_t arrival_time_ms) {
206 if (ShouldRecord(arrival_time_ms)) {
207 delays_ms_.push_back(delay_ms);
208 }
209 }
210
211 void MetricRecorder::PushThroughputBytes(size_t payload_size,
212 int64_t arrival_time_ms) {
213 if (ShouldRecord(arrival_time_ms)) {
214 throughput_bytes_.push_back(payload_size);
215
216 int64_t current_available_per_flow_kbps =
217 static_cast<int64_t>(GetAvailablePerFlowKbps());
218
219 int64_t current_bitrate_diff_kbps =
220 static_cast<int64_t>(GetSendingEstimateKbps()) -
221 current_available_per_flow_kbps;
222
223 // now_ms_ was still not updated here.
224 weighted_estimate_error_.push_back(
225 ((current_bitrate_diff_kbps + last_unweighted_estimate_error_) *
226 (arrival_time_ms - now_ms_)) /
227 2);
228
229 optimal_throughput_bits_ += ((current_available_per_flow_kbps +
230 last_available_bitrate_per_flow_kbps_) *
231 (arrival_time_ms - now_ms_)) /
232 2;
233 }
234 }
235
236 bool MetricRecorder::ShouldRecord(int64_t arrival_time_ms) {
237 if (arrival_time_ms >= start_computing_metrics_ms_) {
238 if (!started_computing_metrics_) {
239 start_computing_metrics_ms_ = arrival_time_ms;
240 now_ms_ = arrival_time_ms;
241 started_computing_metrics_ = true;
242 }
243 return true;
244 } else {
245 return false;
246 }
247 }
248
249 // The weighted_estimate_error_ was weighted based on time windows.
250 // This function scales back the result before plotting.
251 double MetricRecorder::Renormalize(double x) {
252 size_t num_packets_received = delays_ms_.size();
253 return (x * num_packets_received) / now_ms_;
254 }
255
256 inline double U(int64_t x, double alpha) {
257 if (alpha == 1.0) {
258 return log(static_cast<double>(x));
259 }
260 return pow(static_cast<double>(x), 1.0 - alpha) / (1.0 - alpha);
261 }
262
263 inline double U(size_t x, double alpha) {
264 return U(static_cast<int64_t>(x), alpha);
265 }
266
267 // TODO(magalhaesc): Update ObjectiveFunction.
268 double MetricRecorder::ObjectiveFunction() {
269 const double kDelta = 0.15; // Delay penalty factor.
270 const double kAlpha = 1.0;
271 const double kBeta = 1.0;
272
273 double throughput_metric = U(Sum(throughput_bytes_), kAlpha);
274 double delay_penalty = kDelta * U(Sum(delays_ms_), kBeta);
275
276 return throughput_metric - delay_penalty;
277 }
278
279 void MetricRecorder::PlotThroughputHistogram(const std::string& title,
280 const std::string& bwe_name,
281 int num_flows,
282 int64_t extra_offset_ms,
283 const std::string optimum_id) {
284 size_t num_packets_received = delays_ms_.size();
285
286 int64_t duration_ms = now_ms_ - start_computing_metrics_ms_ - extra_offset_ms;
287
288 double average_bitrate_kbps =
289 static_cast<double>(8 * Sum(throughput_bytes_) / duration_ms);
290
291 double optimal_bitrate_per_flow_kbps =
292 static_cast<double>(optimal_throughput_bits_ / duration_ms);
293
294 std::vector<int64_t> positive = PositiveFilter(weighted_estimate_error_);
295 std::vector<int64_t> negative = NegativeFilter(weighted_estimate_error_);
296
297 double p_error = Renormalize(NormLp(positive, num_packets_received, 1.0));
298 double n_error = Renormalize(NormLp(negative, num_packets_received, 1.0));
299
300 // Prevent the error to be too close to zero (plotting issue).
301 double extra_error = average_bitrate_kbps / 500;
302
303 std::string optimum_title =
304 optimum_id.empty() ? "optimal_bitrate" : "optimal_bitrates#" + optimum_id;
305
306 BWE_TEST_LOGGING_LABEL(4, title, "average_bitrate_(kbps)", num_flows);
307 BWE_TEST_LOGGING_LIMITERRORBAR(
308 4, bwe_name, average_bitrate_kbps,
309 average_bitrate_kbps - n_error - extra_error,
310 average_bitrate_kbps + p_error + extra_error, "estimate_error",
311 optimal_bitrate_per_flow_kbps, optimum_title, flow_id_);
312
313 // Silencing unused variable compiling error.
314 RTC_UNUSED(p_error);
315 RTC_UNUSED(n_error);
316 RTC_UNUSED(extra_error);
317 RTC_UNUSED(optimal_bitrate_per_flow_kbps);
318 }
319
320 void MetricRecorder::PlotThroughputHistogram(const std::string& title,
321 const std::string& bwe_name,
322 int num_flows,
323 int64_t extra_offset_ms) {
324 PlotThroughputHistogram(title, bwe_name, num_flows, extra_offset_ms, "");
325 }
326
327 void MetricRecorder::PlotDelayHistogram(const std::string& title,
328 const std::string& bwe_name,
329 int num_flows) {
330 size_t num_packets_received = delays_ms_.size();
331 double average_delay_ms = Average(delays_ms_, num_packets_received);
332
333 // Prevent the error to be too close to zero (plotting issue).
334 double extra_error = average_delay_ms / 500;
335
336 double tenth_sigma_ms =
337 StandardDeviation(delays_ms_, num_packets_received) / 10.0 + extra_error;
338
339 BWE_TEST_LOGGING_LABEL(5, title, "average_delay_(ms)", num_flows)
340 BWE_TEST_LOGGING_ERRORBAR(
341 5, bwe_name, average_delay_ms, average_delay_ms - tenth_sigma_ms,
342 average_delay_ms + tenth_sigma_ms, "sigma/10", flow_id_);
343
344 // Silencing unused variable compiling error.
345 RTC_UNUSED(tenth_sigma_ms);
346 }
347
348 void MetricRecorder::PlotLossHistogram(const std::string& title,
349 const std::string& bwe_name,
350 int num_flows,
351 float global_loss_ratio) {
352 BWE_TEST_LOGGING_LABEL(6, title, "packet_loss_ratio_(%)", num_flows)
353 BWE_TEST_LOGGING_BAR(6, bwe_name, 100.0f * global_loss_ratio, flow_id_);
354 }
355
356 void MetricRecorder::PlotObjectiveHistogram(const std::string& title,
357 const std::string& bwe_name,
358 int num_flows) {
359 BWE_TEST_LOGGING_LABEL(7, title, "objective_function", num_flows)
360 BWE_TEST_LOGGING_BAR(7, bwe_name, ObjectiveFunction(), flow_id_);
361 }
362
363 } // namespace bwe
364 } // namespace testing
365 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698