| Index: webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc
|
| diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc
|
| index 182f93193e6d98755ffedc0dd973e78a961043aa..d06f8546984636d5797690eaaa6e6be5dceb0fad 100644
|
| --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc
|
| +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc
|
| @@ -10,10 +10,13 @@
|
|
|
| #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h"
|
|
|
| +#include <sstream>
|
| +
|
| #include "webrtc/base/common.h"
|
| #include "webrtc/base/scoped_ptr.h"
|
| #include "webrtc/modules/interface/module_common_types.h"
|
| #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
|
| +#include "webrtc/modules/remote_bitrate_estimator/test/metric_recorder.h"
|
| #include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h"
|
| #include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h"
|
| #include "webrtc/system_wrappers/interface/clock.h"
|
| @@ -90,7 +93,10 @@ void PacketProcessorRunner::QueuePackets(Packets* batch,
|
| }
|
|
|
| BweTest::BweTest()
|
| - : run_time_ms_(0), time_now_ms_(-1), simulation_interval_ms_(-1) {
|
| + : run_time_ms_(0),
|
| + time_now_ms_(-1),
|
| + simulation_interval_ms_(-1),
|
| + plot_total_available_capacity_(true) {
|
| links_.push_back(&uplink_);
|
| links_.push_back(&downlink_);
|
| }
|
| @@ -235,7 +241,10 @@ void BweTest::RunFairnessTest(BandwidthEstimatorType bwe_type,
|
| size_t num_tcp_flows,
|
| int64_t run_time_seconds,
|
| int capacity_kbps,
|
| - int max_delay_ms) {
|
| + int64_t max_delay_ms,
|
| + int64_t rtt_ms,
|
| + int64_t max_jitter_ms,
|
| + const int64_t* offsets_ms) {
|
| std::set<int> all_flow_ids;
|
| std::set<int> media_flow_ids;
|
| std::set<int> tcp_flow_ids;
|
| @@ -253,27 +262,34 @@ void BweTest::RunFairnessTest(BandwidthEstimatorType bwe_type,
|
|
|
| std::vector<VideoSource*> sources;
|
| std::vector<PacketSender*> senders;
|
| + std::vector<MetricRecorder*> metric_recorders;
|
| +
|
| + int64_t max_offset_ms = 0;
|
| + size_t i = 0;
|
|
|
| - size_t i = 1;
|
| for (int media_flow : media_flow_ids) {
|
| - // Streams started 20 seconds apart to give them different advantage when
|
| - // competing for the bandwidth.
|
| - const int64_t kFlowStartOffsetMs = i++ * (rand() % 10000);
|
| - sources.push_back(new AdaptiveVideoSource(media_flow, 30, 300, 0,
|
| - kFlowStartOffsetMs));
|
| + sources.push_back(
|
| + new AdaptiveVideoSource(media_flow, 30, 300, 0, offsets_ms[i]));
|
| senders.push_back(new PacedVideoSender(&uplink_, sources.back(), bwe_type));
|
| + max_offset_ms = std::max(max_offset_ms, offsets_ms[i++]);
|
| }
|
|
|
| const int64_t kTcpStartOffsetMs = 5000;
|
| + max_offset_ms = std::max(max_offset_ms, kTcpStartOffsetMs);
|
| for (int tcp_flow : tcp_flow_ids)
|
| senders.push_back(new TcpSender(&uplink_, tcp_flow, kTcpStartOffsetMs));
|
|
|
| ChokeFilter choke(&uplink_, all_flow_ids);
|
| choke.set_capacity_kbps(capacity_kbps);
|
| choke.set_max_delay_ms(max_delay_ms);
|
| + LinkShare link_share(&choke);
|
|
|
| + int64_t one_way_delay_ms = rtt_ms / 2;
|
| DelayFilter delay_uplink(&uplink_, all_flow_ids);
|
| - delay_uplink.SetOneWayDelayMs(25);
|
| + delay_uplink.SetOneWayDelayMs(one_way_delay_ms);
|
| +
|
| + JitterFilter jitter(&uplink_, all_flow_ids);
|
| + jitter.SetMaxJitter(max_jitter_ms);
|
|
|
| std::vector<RateCounterFilter*> rate_counters;
|
| for (int flow : all_flow_ids) {
|
| @@ -286,17 +302,33 @@ void BweTest::RunFairnessTest(BandwidthEstimatorType bwe_type,
|
|
|
| std::vector<PacketReceiver*> receivers;
|
| i = 0;
|
| + // Delays is being plotted only for the first flow.
|
| + // To plot all of them, replace "i == 0" with "true" on new PacketReceiver().
|
| for (int media_flow : media_flow_ids) {
|
| - receivers.push_back(
|
| - new PacketReceiver(&uplink_, media_flow, bwe_type, i++ == 0, false));
|
| + metric_recorders.push_back(new MetricRecorder(
|
| + bwe_names[bwe_type], static_cast<int>(i), senders[i], &link_share));
|
| + receivers.push_back(new PacketReceiver(&uplink_, media_flow, bwe_type,
|
| + i == 0, false, metric_recorders[i]));
|
| + metric_recorders[i]->set_plot_available_capacity(
|
| + i == 0 && plot_total_available_capacity_);
|
| + metric_recorders[i]->set_start_computing_metrics_ms(max_offset_ms);
|
| + ++i;
|
| }
|
| + // Delays is not being plotted only for TCP flows. To plot all of them,
|
| + // replace first "false" occurence with "true" on new PacketReceiver().
|
| for (int tcp_flow : tcp_flow_ids) {
|
| - receivers.push_back(
|
| - new PacketReceiver(&uplink_, tcp_flow, kTcpEstimator, false, false));
|
| + metric_recorders.push_back(new MetricRecorder(bwe_names[kTcpEstimator],
|
| + static_cast<int>(i),
|
| + senders[i], &link_share));
|
| + receivers.push_back(new PacketReceiver(&uplink_, tcp_flow, kTcpEstimator,
|
| + false, false, metric_recorders[i]));
|
| + metric_recorders[i]->set_plot_available_capacity(
|
| + i == 0 && plot_total_available_capacity_);
|
| + ++i;
|
| }
|
|
|
| DelayFilter delay_downlink(&downlink_, all_flow_ids);
|
| - delay_downlink.SetOneWayDelayMs(25);
|
| + delay_downlink.SetOneWayDelayMs(one_way_delay_ms);
|
|
|
| RunFor(run_time_seconds * 1000);
|
|
|
| @@ -315,6 +347,19 @@ void BweTest::RunFairnessTest(BandwidthEstimatorType bwe_type,
|
| PrintResults(capacity_kbps, total_utilization.GetBitrateStats(),
|
| flow_delay_ms, flow_throughput_kbps);
|
|
|
| + std::string title("5.4_Self_fairness_test");
|
| + for (size_t i = 0; i < num_media_flows; ++i) {
|
| + metric_recorders[i]->PlotThroughputHistogram(
|
| + title, bwe_names[bwe_type], static_cast<int>(num_media_flows), 0);
|
| + metric_recorders[i]->PlotDelayHistogram(title, bwe_names[bwe_type],
|
| + static_cast<int>(num_media_flows),
|
| + one_way_delay_ms);
|
| + metric_recorders[i]->PlotLossHistogram(title, bwe_names[bwe_type],
|
| + static_cast<int>(num_media_flows),
|
| + receivers[i]->GlobalPacketLoss());
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], one_way_delay_ms, i);
|
| + }
|
| +
|
| for (VideoSource* source : sources)
|
| delete source;
|
| for (PacketSender* sender : senders)
|
| @@ -323,7 +368,638 @@ void BweTest::RunFairnessTest(BandwidthEstimatorType bwe_type,
|
| delete rate_counter;
|
| for (PacketReceiver* receiver : receivers)
|
| delete receiver;
|
| + for (MetricRecorder* recorder : metric_recorders)
|
| + delete recorder;
|
| +}
|
| +
|
| +void BweTest::RunChoke(BandwidthEstimatorType bwe_type,
|
| + std::vector<int> capacities_kbps) {
|
| + int flow_id = bwe_type;
|
| + AdaptiveVideoSource source(flow_id, 30, 300, 0, 0);
|
| + VideoSender sender(&uplink_, &source, bwe_type);
|
| + ChokeFilter choke(&uplink_, flow_id);
|
| + LinkShare link_share(&choke);
|
| + MetricRecorder metric_recorder(bwe_names[bwe_type], flow_id, &sender,
|
| + &link_share);
|
| + RateCounterFilter counter(&uplink_, flow_id, "receiver_input");
|
| + PacketReceiver receiver(&uplink_, flow_id, bwe_type, true, false,
|
| + &metric_recorder);
|
| + metric_recorder.set_plot_available_capacity(plot_total_available_capacity_);
|
| +
|
| + choke.set_max_delay_ms(500);
|
| + const int64_t kRunTimeMs = 60 * 1000;
|
| +
|
| + std::stringstream title("Choke");
|
| + char delimiter = '_';
|
| +
|
| + for (auto it = capacities_kbps.begin(); it != capacities_kbps.end(); ++it) {
|
| + choke.set_capacity_kbps(*it);
|
| + RunFor(kRunTimeMs);
|
| + title << delimiter << (*it);
|
| + delimiter = '-';
|
| + }
|
| +
|
| + title << "_kbps,_" << (kRunTimeMs / 1000) << "s_each";
|
| + metric_recorder.PlotThroughputHistogram(title.str(), bwe_names[bwe_type], 1,
|
| + 0);
|
| + metric_recorder.PlotDelayHistogram(title.str(), bwe_names[bwe_type], 1, 0);
|
| + // receiver.PlotLossHistogram(title, bwe_names[bwe_type], 1);
|
| + // receiver.PlotObjectiveHistogram(title, bwe_names[bwe_type], 1);
|
| +}
|
| +
|
| +// 5.1. Single Video and Audio media traffic, forward direction.
|
| +void BweTest::RunVariableCapacitySingleFlow(BandwidthEstimatorType bwe_type) {
|
| + const int kFlowId = 0; // Arbitrary value.
|
| + AdaptiveVideoSource source(kFlowId, 30, 300, 0, 0);
|
| + PacedVideoSender sender(&uplink_, &source, bwe_type);
|
| + DefaultEvaluationFilter up_filter(&uplink_, kFlowId);
|
| + DelayFilter down_filter(&downlink_, kFlowId);
|
| + LinkShare link_share(&(up_filter.choke));
|
| + MetricRecorder metric_recorder(bwe_names[bwe_type], kFlowId, &sender,
|
| + &link_share);
|
| + RateCounterFilter counter(&uplink_, kFlowId, "receiver_input");
|
| + PacketReceiver receiver(&uplink_, kFlowId, bwe_type, true, true,
|
| + &metric_recorder);
|
| + metric_recorder.set_plot_available_capacity(plot_total_available_capacity_);
|
| +
|
| + down_filter.SetOneWayDelayMs(kOneWayDelayMs);
|
| + // up_filter.jitter.SetMaxJitter(0);
|
| +
|
| + // Test also with one way propagation delay = 100ms.
|
| + // up_filter.delay.SetOneWayDelayMs(100);
|
| + // down_filter.SetOneWayDelayMs(100);
|
| +
|
| + up_filter.choke.set_capacity_kbps(1000);
|
| + RunFor(40 * 1000); // 0-40s.
|
| + up_filter.choke.set_capacity_kbps(2500);
|
| + RunFor(20 * 1000); // 40-60s.
|
| + up_filter.choke.set_capacity_kbps(600);
|
| + RunFor(20 * 1000); // 60-80s.
|
| + up_filter.choke.set_capacity_kbps(1000);
|
| + RunFor(20 * 1000); // 80-100s.
|
| +
|
| + std::string title("5.1_Variable_capacity_single_flow");
|
| + metric_recorder.PlotThroughputHistogram(title, bwe_names[bwe_type], 1, 0);
|
| + metric_recorder.PlotDelayHistogram(title, bwe_names[bwe_type], 1,
|
| + kOneWayDelayMs);
|
| + metric_recorder.PlotLossHistogram(title, bwe_names[bwe_type], 1,
|
| + receiver.GlobalPacketLoss());
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], kOneWayDelayMs, kFlowId);
|
| +}
|
| +
|
| +// 5.2. Two forward direction competing flows, variable capacity.
|
| +void BweTest::RunVariableCapacityTwoFlows(BandwidthEstimatorType bwe_type) {
|
| + const int kAllFlowIds[] = {0, 1}; // Two RMCAT flows.
|
| + const size_t kNumFlows = ARRAY_SIZE(kAllFlowIds);
|
| +
|
| + rtc::scoped_ptr<AdaptiveVideoSource> sources[kNumFlows];
|
| + rtc::scoped_ptr<VideoSender> senders[kNumFlows];
|
| + rtc::scoped_ptr<MetricRecorder> metric_recorders[kNumFlows];
|
| + rtc::scoped_ptr<PacketReceiver> receivers[kNumFlows];
|
| +
|
| + const int64_t kStartingApartMs = 0; // Flows initialized simultaneously.
|
| +
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + sources[i].reset(new AdaptiveVideoSource(kAllFlowIds[i], 30, 300, 0,
|
| + i * kStartingApartMs));
|
| + senders[i].reset(new VideoSender(&uplink_, sources[i].get(), bwe_type));
|
| + }
|
| +
|
| + DefaultEvaluationFilter up_filter(&uplink_,
|
| + CreateFlowIds(kAllFlowIds, kNumFlows));
|
| +
|
| + LinkShare link_share(&(up_filter.choke));
|
| +
|
| + DelayFilter down_filter(&downlink_, CreateFlowIds(kAllFlowIds, kNumFlows));
|
| +
|
| + rtc::scoped_ptr<RateCounterFilter> rate_counters[kNumFlows];
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + rate_counters[i].reset(new RateCounterFilter(
|
| + &uplink_, CreateFlowIds(&kAllFlowIds[i], 1), "receiver_input"));
|
| + }
|
| +
|
| + RateCounterFilter total_utilization(
|
| + &uplink_, CreateFlowIds(kAllFlowIds, kNumFlows), "total_utilization");
|
| +
|
| + // Delays is being plotted only for the first flow.
|
| + // To plot all of them, replace "i == 0" with "true" on new PacketReceiver().
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].reset(
|
| + new MetricRecorder(bwe_names[bwe_type], static_cast<int>(i),
|
| + senders[i].get(), &link_share));
|
| +
|
| + receivers[i].reset(new PacketReceiver(&uplink_, kAllFlowIds[i], bwe_type,
|
| + i == 0, false,
|
| + metric_recorders[i].get()));
|
| + metric_recorders[i].get()->set_plot_available_capacity(
|
| + i == 0 && plot_total_available_capacity_);
|
| + }
|
| +
|
| + down_filter.SetOneWayDelayMs(kOneWayDelayMs);
|
| + // Test also with one way propagation delay = 100ms.
|
| + // up_filter.delay.SetOneWayDelayMs(100);
|
| + // down_filter.SetOneWayDelayMs(100);
|
| +
|
| + up_filter.choke.set_capacity_kbps(4000);
|
| + RunFor(25 * 1000); // 0-25s.
|
| + up_filter.choke.set_capacity_kbps(2000);
|
| + RunFor(25 * 1000); // 25-50s.
|
| + up_filter.choke.set_capacity_kbps(3500);
|
| + RunFor(25 * 1000); // 50-75s.
|
| + up_filter.choke.set_capacity_kbps(1000);
|
| + RunFor(25 * 1000); // 75-100s.
|
| + up_filter.choke.set_capacity_kbps(2000);
|
| + RunFor(25 * 1000); // 100-125s.
|
| +
|
| + std::string title("5.2_Variable_capacity_two_flows");
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].get()->PlotThroughputHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows, 0);
|
| + metric_recorders[i].get()->PlotDelayHistogram(title, bwe_names[bwe_type],
|
| + kNumFlows, kOneWayDelayMs);
|
| + metric_recorders[i].get()->PlotLossHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows,
|
| + receivers[i].get()->GlobalPacketLoss());
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], kOneWayDelayMs, i);
|
| + }
|
| +}
|
| +
|
| +// 5.3. Bi-directional RMCAT flows.
|
| +void BweTest::RunBidirectionalFlow(BandwidthEstimatorType bwe_type) {
|
| + enum direction { kForward = 0, kBackward };
|
| + const size_t kNumFlows = 2;
|
| + rtc::scoped_ptr<AdaptiveVideoSource> sources[kNumFlows];
|
| + rtc::scoped_ptr<VideoSender> senders[kNumFlows];
|
| + rtc::scoped_ptr<MetricRecorder> metric_recorders[kNumFlows];
|
| + rtc::scoped_ptr<RateCounterFilter> rate_counters[kNumFlows];
|
| + rtc::scoped_ptr<PacketReceiver> receivers[kNumFlows];
|
| +
|
| + sources[kForward].reset(new AdaptiveVideoSource(kForward, 30, 300, 0, 0));
|
| + senders[kForward].reset(
|
| + new VideoSender(&uplink_, sources[kForward].get(), bwe_type));
|
| +
|
| + sources[kBackward].reset(new AdaptiveVideoSource(kBackward, 30, 300, 0, 0));
|
| + senders[kBackward].reset(
|
| + new VideoSender(&downlink_, sources[kBackward].get(), bwe_type));
|
| +
|
| + DefaultEvaluationFilter up_filter(&uplink_, kForward);
|
| + DefaultEvaluationFilter down_filter(&downlink_, kBackward);
|
| + LinkShare up_link_share(&(up_filter.choke));
|
| + LinkShare down_link_share(&(down_filter.choke));
|
| +
|
| + metric_recorders[kForward].reset(new MetricRecorder(
|
| + bwe_names[bwe_type], kForward, senders[kForward].get(), &up_link_share));
|
| + rate_counters[kForward].reset(
|
| + new RateCounterFilter(&uplink_, kForward, "fwd_receiver_input"));
|
| + receivers[kForward].reset(
|
| + new PacketReceiver(&uplink_, kForward, bwe_type, true, false,
|
| + metric_recorders[kForward].get()));
|
| +
|
| + metric_recorders[kForward].get()->set_plot_available_capacity(
|
| + plot_total_available_capacity_);
|
| +
|
| + metric_recorders[kBackward].reset(
|
| + new MetricRecorder(bwe_names[bwe_type], kBackward,
|
| + senders[kBackward].get(), &down_link_share));
|
| + rate_counters[kBackward].reset(
|
| + new RateCounterFilter(&downlink_, kBackward, "bwd_receiver_input"));
|
| + receivers[kBackward].reset(
|
| + new PacketReceiver(&downlink_, kBackward, bwe_type, true, false,
|
| + metric_recorders[kBackward].get()));
|
| +
|
| + metric_recorders[kBackward].get()->set_plot_available_capacity(
|
| + plot_total_available_capacity_);
|
| +
|
| + // Test also with one way propagation delay = 100ms.
|
| + // up_filter.delay.SetOneWayDelayMs(100);
|
| + // down_filter.delay.SetOneWayDelayMs(100);
|
| +
|
| + up_filter.choke.set_capacity_kbps(2000);
|
| + down_filter.choke.set_capacity_kbps(2000);
|
| + RunFor(20 * 1000); // 0-20s.
|
| +
|
| + up_filter.choke.set_capacity_kbps(1000);
|
| + RunFor(15 * 1000); // 20-35s.
|
| +
|
| + down_filter.choke.set_capacity_kbps(800);
|
| + RunFor(5 * 1000); // 35-40s.
|
| +
|
| + up_filter.choke.set_capacity_kbps(500);
|
| + RunFor(20 * 1000); // 40-60s.
|
| +
|
| + up_filter.choke.set_capacity_kbps(2000);
|
| + RunFor(10 * 1000); // 60-70s.
|
| +
|
| + down_filter.choke.set_capacity_kbps(2000);
|
| + RunFor(30 * 1000); // 70-100s.
|
| +
|
| + std::string title("5.3_Bidirectional_flows");
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].get()->PlotThroughputHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows, 0);
|
| + metric_recorders[i].get()->PlotDelayHistogram(title, bwe_names[bwe_type],
|
| + kNumFlows, kOneWayDelayMs);
|
| + metric_recorders[i].get()->PlotLossHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows,
|
| + receivers[i].get()->GlobalPacketLoss());
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], kOneWayDelayMs, i);
|
| + }
|
| +}
|
| +
|
| +// 5.5. Five competing RMCAT flows under different RTTs.
|
| +void BweTest::RunRoundTripTimeFairness(BandwidthEstimatorType bwe_type) {
|
| + const int kAllFlowIds[] = {0, 1, 2, 3, 4}; // Five RMCAT flows.
|
| + const int64_t kAllOneWayDelayMs[] = {10, 25, 50, 100, 150};
|
| + const size_t kNumFlows = ARRAY_SIZE(kAllFlowIds);
|
| + rtc::scoped_ptr<AdaptiveVideoSource> sources[kNumFlows];
|
| + rtc::scoped_ptr<VideoSender> senders[kNumFlows];
|
| + rtc::scoped_ptr<MetricRecorder> metric_recorders[kNumFlows];
|
| +
|
| + // Flows initialized 10 seconds apart.
|
| + const int64_t kStartingApartMs = 10 * 1000;
|
| +
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + sources[i].reset(new AdaptiveVideoSource(kAllFlowIds[i], 30, 300, 0,
|
| + i * kStartingApartMs));
|
| + senders[i].reset(new VideoSender(&uplink_, sources[i].get(), bwe_type));
|
| + }
|
| +
|
| + ChokeFilter choke_filter(&uplink_, CreateFlowIds(kAllFlowIds, kNumFlows));
|
| + JitterFilter jitter_filter(&uplink_, CreateFlowIds(kAllFlowIds, kNumFlows));
|
| + rtc::scoped_ptr<DelayFilter> up_delay_filters[kNumFlows];
|
| + rtc::scoped_ptr<DelayFilter> down_delay_filters[kNumFlows];
|
| +
|
| + LinkShare link_share(&choke_filter);
|
| +
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + up_delay_filters[i].reset(new DelayFilter(&uplink_, kAllFlowIds[i]));
|
| + down_delay_filters[i].reset(new DelayFilter(&downlink_, kAllFlowIds[i]));
|
| + }
|
| +
|
| + rtc::scoped_ptr<RateCounterFilter> rate_counters[kNumFlows];
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + rate_counters[i].reset(
|
| + new RateCounterFilter(&uplink_, CreateFlowIds(&kAllFlowIds[i], 1),
|
| + "receiver_input", i * kStartingApartMs));
|
| + }
|
| +
|
| + RateCounterFilter total_utilization(
|
| + &uplink_, CreateFlowIds(kAllFlowIds, kNumFlows), "total_utilization");
|
| +
|
| + // Delays is being plotted only for the first flow.
|
| + // To plot all of them, replace "i == 0" with "true" on new PacketReceiver().
|
| + rtc::scoped_ptr<PacketReceiver> receivers[kNumFlows];
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].reset(
|
| + new MetricRecorder(bwe_names[bwe_type], static_cast<int>(i),
|
| + senders[i].get(), &link_share));
|
| +
|
| + receivers[i].reset(new PacketReceiver(&uplink_, kAllFlowIds[i], bwe_type,
|
| + i == 0, false,
|
| + metric_recorders[i].get()));
|
| + metric_recorders[i].get()->set_start_computing_metrics_ms(kStartingApartMs *
|
| + (kNumFlows - 1));
|
| + metric_recorders[i].get()->set_plot_available_capacity(
|
| + i == 0 && plot_total_available_capacity_);
|
| + }
|
| +
|
| + jitter_filter.SetMaxJitter(kMaxJitterMs);
|
| + choke_filter.set_max_delay_ms(kMaxQueueingDelayMs);
|
| +
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + up_delay_filters[i]->SetOneWayDelayMs(kAllOneWayDelayMs[i]);
|
| + down_delay_filters[i]->SetOneWayDelayMs(kAllOneWayDelayMs[i]);
|
| + }
|
| +
|
| + choke_filter.set_capacity_kbps(3500);
|
| +
|
| + RunFor(300 * 1000); // 0-300s.
|
| +
|
| + std::string title("5.5_Round_Trip_Time_Fairness");
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].get()->PlotThroughputHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows, 0);
|
| + metric_recorders[i].get()->PlotDelayHistogram(title, bwe_names[bwe_type],
|
| + kNumFlows, kOneWayDelayMs);
|
| + metric_recorders[i].get()->PlotLossHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows,
|
| + receivers[i].get()->GlobalPacketLoss());
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], kAllOneWayDelayMs[i],
|
| + i);
|
| + }
|
| +}
|
| +
|
| +// 5.6. RMCAT Flow competing with a long TCP Flow.
|
| +void BweTest::RunLongTcpFairness(BandwidthEstimatorType bwe_type) {
|
| + enum flow_ids { kRmcatId = 0, kTcpId };
|
| + const size_t kNumFlows = 2;
|
| +
|
| + rtc::scoped_ptr<PacketSender> senders[kNumFlows];
|
| + rtc::scoped_ptr<MetricRecorder> metric_recorders[kNumFlows];
|
| + rtc::scoped_ptr<PacketReceiver> receivers[kNumFlows];
|
| +
|
| + // Flows initialized 5 seconds apart.
|
| + const int64_t kStartingApartMs = 5 * 1000;
|
| +
|
| + // Starting at t=0;
|
| + senders[kTcpId].reset(new TcpSender(&uplink_, kTcpId, 0));
|
| +
|
| + AdaptiveVideoSource rmcat_source(kRmcatId, 30, 300, 0, kStartingApartMs);
|
| + senders[kRmcatId].reset(new VideoSender(&uplink_, &rmcat_source, bwe_type));
|
| +
|
| + DefaultEvaluationFilter up_filter(&uplink_,
|
| + CreateFlowIdRange(kRmcatId, kTcpId));
|
| + DelayFilter down_filter(&downlink_, CreateFlowIdRange(kRmcatId, kTcpId));
|
| +
|
| + LinkShare link_share(&(up_filter.choke));
|
| +
|
| + rtc::scoped_ptr<RateCounterFilter> rate_counters[kNumFlows];
|
| + for (int id = kRmcatId; id <= kTcpId; ++id) {
|
| + rate_counters[id].reset(
|
| + new RateCounterFilter(&uplink_, id, "receiver_input"));
|
| + }
|
| +
|
| + RateCounterFilter total_utilization(
|
| + &uplink_, CreateFlowIdRange(kRmcatId, kTcpId), "total_utilization");
|
| +
|
| + metric_recorders[kTcpId].reset(new MetricRecorder(
|
| + bwe_names[kTcpEstimator], kTcpId, senders[kTcpId].get(), &link_share));
|
| + receivers[kTcpId].reset(new PacketReceiver(&uplink_, kTcpId, kTcpEstimator,
|
| + true, false,
|
| + metric_recorders[kTcpId].get()));
|
| + metric_recorders[kTcpId].get()->set_start_computing_metrics_ms(
|
| + kStartingApartMs);
|
| + metric_recorders[kTcpId].get()->set_plot_available_capacity(
|
| + plot_total_available_capacity_);
|
| +
|
| + metric_recorders[kRmcatId].reset(new MetricRecorder(
|
| + bwe_names[bwe_type], kRmcatId, senders[kRmcatId].get(), &link_share));
|
| + receivers[kRmcatId].reset(
|
| + new PacketReceiver(&uplink_, kRmcatId, bwe_type, true, false,
|
| + metric_recorders[kRmcatId].get()));
|
| + metric_recorders[kRmcatId].get()->set_start_computing_metrics_ms(
|
| + kStartingApartMs);
|
| + metric_recorders[kRmcatId].get()->set_plot_available_capacity(false);
|
| +
|
| + down_filter.SetOneWayDelayMs(kOneWayDelayMs);
|
| + // Test also with one way propagation delay = 100ms.
|
| + // up_filter.delay.SetOneWayDelayMs(100);
|
| + // down_filter.SetOneWayDelayMs(100);
|
| +
|
| + // Test also with bottleneck queue size = 20ms and 1000ms.
|
| + // up_filter.choke.set_max_delay_ms(20);
|
| + // up_filter.choke.set_max_delay_ms(1000);
|
| +
|
| + // Test also with no Jitter:
|
| + // up_filter.jitter.SetMaxJitter(0);
|
| +
|
| + up_filter.choke.set_capacity_kbps(2000);
|
| +
|
| + RunFor(120 * 1000); // 0-120s.
|
| +
|
| + std::string title("5.6_Long_TCP_Fairness");
|
| + std::string flow_name(bwe_names[bwe_type] + 'x' + bwe_names[kTcpEstimator]);
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].get()->PlotThroughputHistogram(title, flow_name,
|
| + kNumFlows, 0);
|
| + metric_recorders[i].get()->PlotLossHistogram(
|
| + title, flow_name, kNumFlows, receivers[i].get()->GlobalPacketLoss());
|
| + }
|
| + // Pointless to show delay plot for TCP flow.
|
| + metric_recorders[kRmcatId].get()->PlotDelayHistogram(
|
| + title, bwe_names[bwe_type], 1, kOneWayDelayMs);
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], kOneWayDelayMs,
|
| + kRmcatId);
|
| }
|
| +
|
| +// 5.7. RMCAT Flows competing with multiple short TCP Flows.
|
| +void BweTest::RunMultipleShortTcpFairness(
|
| + BandwidthEstimatorType bwe_type,
|
| + std::vector<int> tcp_file_sizes_bytes,
|
| + std::vector<int64_t> tcp_starting_times_ms) {
|
| + // Two RMCAT flows and ten TCP flows.
|
| + const int kAllRmcatFlowIds[] = {0, 1};
|
| + const int kAllTcpFlowIds[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
| +
|
| + assert(tcp_starting_times_ms.size() == tcp_file_sizes_bytes.size() &&
|
| + tcp_starting_times_ms.size() == ARRAY_SIZE(kAllTcpFlowIds));
|
| +
|
| + const size_t kNumRmcatFlows = ARRAY_SIZE(kAllRmcatFlowIds);
|
| + const size_t kNumTotalFlows = kNumRmcatFlows + ARRAY_SIZE(kAllTcpFlowIds);
|
| +
|
| + rtc::scoped_ptr<AdaptiveVideoSource> sources[kNumRmcatFlows];
|
| + rtc::scoped_ptr<PacketSender> senders[kNumTotalFlows];
|
| + rtc::scoped_ptr<MetricRecorder> metric_recorders[kNumTotalFlows];
|
| + rtc::scoped_ptr<PacketReceiver> receivers[kNumTotalFlows];
|
| +
|
| + // RMCAT Flows are initialized simultaneosly at t=5 seconds.
|
| + const int64_t kRmcatStartingTimeMs = 5 * 1000;
|
| + for (size_t id : kAllRmcatFlowIds) {
|
| + sources[id].reset(new AdaptiveVideoSource(static_cast<int>(id), 30, 300, 0,
|
| + kRmcatStartingTimeMs));
|
| + senders[id].reset(new VideoSender(&uplink_, sources[id].get(), bwe_type));
|
| + }
|
| +
|
| + for (size_t id : kAllTcpFlowIds) {
|
| + senders[id].reset(new TcpSender(&uplink_, static_cast<int>(id),
|
| + tcp_starting_times_ms[id - kNumRmcatFlows],
|
| + tcp_file_sizes_bytes[id - kNumRmcatFlows]));
|
| + }
|
| +
|
| + FlowIds flow_ids = CreateFlowIdRange(0, static_cast<int>(kNumTotalFlows - 1));
|
| + DefaultEvaluationFilter up_filter(&uplink_, flow_ids);
|
| + DelayFilter down_filter(&downlink_, flow_ids);
|
| +
|
| + LinkShare link_share(&(up_filter.choke));
|
| +
|
| + rtc::scoped_ptr<RateCounterFilter> rate_counters[kNumTotalFlows];
|
| + for (size_t id = 0; id < kNumTotalFlows; ++id) {
|
| + rate_counters[id].reset(new RateCounterFilter(
|
| + &uplink_, static_cast<int>(id), "receiver_input"));
|
| + }
|
| +
|
| + RateCounterFilter total_utilization(&uplink_, flow_ids, "total_utilization");
|
| +
|
| + // Delays is being plotted only for the first flow.
|
| + // To plot all of them, replace "i == 0" with "true" on new PacketReceiver().
|
| + for (size_t id : kAllRmcatFlowIds) {
|
| + metric_recorders[id].reset(
|
| + new MetricRecorder(bwe_names[bwe_type], static_cast<int>(id),
|
| + senders[id].get(), &link_share));
|
| + receivers[id].reset(new PacketReceiver(&uplink_, static_cast<int>(id),
|
| + bwe_type, id == 0, false,
|
| + metric_recorders[id].get()));
|
| + metric_recorders[id].get()->set_start_computing_metrics_ms(
|
| + kRmcatStartingTimeMs);
|
| + metric_recorders[id].get()->set_plot_available_capacity(
|
| + id == 0 && plot_total_available_capacity_);
|
| + }
|
| +
|
| + // Delays is not being plotted only for TCP flows. To plot all of them,
|
| + // replace first "false" occurence with "true" on new PacketReceiver().
|
| + for (size_t id : kAllTcpFlowIds) {
|
| + metric_recorders[id].reset(
|
| + new MetricRecorder(bwe_names[kTcpEstimator], static_cast<int>(id),
|
| + senders[id].get(), &link_share));
|
| + receivers[id].reset(new PacketReceiver(&uplink_, static_cast<int>(id),
|
| + kTcpEstimator, false, false,
|
| + metric_recorders[id].get()));
|
| + metric_recorders[id].get()->set_plot_available_capacity(
|
| + id == 0 && plot_total_available_capacity_);
|
| + }
|
| +
|
| + down_filter.SetOneWayDelayMs(kOneWayDelayMs);
|
| +
|
| + // Test also with one way propagation delay = 100ms.
|
| + // up_filter.delay.SetOneWayDelayMs(100);
|
| + // down_filter.SetOneWayDelayms(100);
|
| +
|
| + // Test also with bottleneck queue size = 20ms and 1000ms.
|
| + // up_filter.choke.set_max_delay_ms(20);
|
| + // up_filter.choke.set_max_delay_ms(1000);
|
| +
|
| + // Test also with no Jitter:
|
| + // up_filter.jitter.SetMaxJitter(0);
|
| +
|
| + up_filter.choke.set_capacity_kbps(2000);
|
| +
|
| + RunFor(300 * 1000); // 0-300s.
|
| +
|
| + std::string title("5.7_Multiple_short_TCP_flows");
|
| + for (size_t id : kAllRmcatFlowIds) {
|
| + metric_recorders[id].get()->PlotThroughputHistogram(
|
| + title, bwe_names[bwe_type], kNumRmcatFlows, 0);
|
| + metric_recorders[id].get()->PlotDelayHistogram(
|
| + title, bwe_names[bwe_type], kNumRmcatFlows, kOneWayDelayMs);
|
| + metric_recorders[id].get()->PlotLossHistogram(
|
| + title, bwe_names[bwe_type], kNumRmcatFlows,
|
| + receivers[id].get()->GlobalPacketLoss());
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], kOneWayDelayMs, id);
|
| + }
|
| +}
|
| +
|
| +// 5.8. Three forward direction competing flows, constant capacity.
|
| +// During the test, one of the flows is paused and later resumed.
|
| +void BweTest::RunPauseResumeFlows(BandwidthEstimatorType bwe_type) {
|
| + const int kAllFlowIds[] = {0, 1, 2}; // Three RMCAT flows.
|
| + const size_t kNumFlows = ARRAY_SIZE(kAllFlowIds);
|
| +
|
| + rtc::scoped_ptr<AdaptiveVideoSource> sources[kNumFlows];
|
| + rtc::scoped_ptr<VideoSender> senders[kNumFlows];
|
| + rtc::scoped_ptr<MetricRecorder> metric_recorders[kNumFlows];
|
| + rtc::scoped_ptr<PacketReceiver> receivers[kNumFlows];
|
| +
|
| + // Flows initialized simultaneously.
|
| + const int64_t kStartingApartMs = 0;
|
| +
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + sources[i].reset(new AdaptiveVideoSource(kAllFlowIds[i], 30, 300, 0,
|
| + i * kStartingApartMs));
|
| + senders[i].reset(new VideoSender(&uplink_, sources[i].get(), bwe_type));
|
| + }
|
| +
|
| + DefaultEvaluationFilter filter(&uplink_,
|
| + CreateFlowIds(kAllFlowIds, kNumFlows));
|
| +
|
| + LinkShare link_share(&(filter.choke));
|
| +
|
| + rtc::scoped_ptr<RateCounterFilter> rate_counters[kNumFlows];
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + rate_counters[i].reset(new RateCounterFilter(
|
| + &uplink_, CreateFlowIds(&kAllFlowIds[i], 1), "receiver_input"));
|
| + }
|
| +
|
| + RateCounterFilter total_utilization(
|
| + &uplink_, CreateFlowIds(kAllFlowIds, kNumFlows), "total_utilization");
|
| +
|
| + // Delays is being plotted only for the first flow.
|
| + // To plot all of them, replace "i == 0" with "true" on new PacketReceiver().
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].reset(
|
| + new MetricRecorder(bwe_names[bwe_type], static_cast<int>(i),
|
| + senders[i].get(), &link_share));
|
| + receivers[i].reset(new PacketReceiver(&uplink_, kAllFlowIds[i], bwe_type,
|
| + i == 0, false,
|
| + metric_recorders[i].get()));
|
| + metric_recorders[i].get()->set_start_computing_metrics_ms(kStartingApartMs *
|
| + (kNumFlows - 1));
|
| + metric_recorders[i].get()->set_plot_available_capacity(
|
| + i == 0 && plot_total_available_capacity_);
|
| + }
|
| +
|
| + // Test also with one way propagation delay = 100ms.
|
| + // filter.delay.SetOneWayDelayMs(100);
|
| + filter.choke.set_capacity_kbps(3500);
|
| +
|
| + RunFor(40 * 1000); // 0-40s.
|
| +
|
| + senders[0].get()->Pause();
|
| + metric_recorders[0].get()->PauseFlow();
|
| + RunFor(20 * 1000); // 40-60s.
|
| +
|
| + senders[0].get()->Resume();
|
| + metric_recorders[0].get()->ResumeFlow(20 * 1000);
|
| + RunFor(60 * 1000); // 60-120s.
|
| +
|
| + int64_t paused[] = {20 * 1000, 0, 0};
|
| +
|
| + // First flow is being paused, hence having a different optimum.
|
| + const std::string optima_lines[] = {"1", "2", "2"};
|
| +
|
| + std::string title("5.8_Pause_and_resume_media_flow");
|
| + for (size_t i = 0; i < kNumFlows; ++i) {
|
| + metric_recorders[i].get()->PlotThroughputHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows, paused[i], optima_lines[i]);
|
| + metric_recorders[i].get()->PlotDelayHistogram(title, bwe_names[bwe_type],
|
| + kNumFlows, kOneWayDelayMs);
|
| + metric_recorders[i].get()->PlotLossHistogram(
|
| + title, bwe_names[bwe_type], kNumFlows,
|
| + receivers[i].get()->GlobalPacketLoss());
|
| + BWE_TEST_LOGGING_BASELINEBAR(5, bwe_names[bwe_type], kOneWayDelayMs, i);
|
| + }
|
| +}
|
| +
|
| +// Following functions are used for randomizing TCP file size and
|
| +// starting time, used on 5.7 RunMultipleShortTcpFairness.
|
| +// They are pseudo-random generators, creating always the same
|
| +// value sequence for a given Random seed.
|
| +
|
| +std::vector<int> BweTest::GetFileSizesBytes(int num_files) {
|
| + // File size chosen from uniform distribution between [100,1000] kB.
|
| + const int kMinKbytes = 100;
|
| + const int kMaxKbytes = 1000;
|
| +
|
| + Random random(0x12345678);
|
| + std::vector<int> tcp_file_sizes_bytes;
|
| +
|
| + while (num_files-- > 0) {
|
| + tcp_file_sizes_bytes.push_back(random.Rand(kMinKbytes, kMaxKbytes) * 1000);
|
| + }
|
| +
|
| + return tcp_file_sizes_bytes;
|
| +}
|
| +
|
| +std::vector<int64_t> BweTest::GetStartingTimesMs(int num_files) {
|
| + // OFF state behaves as an exp. distribution with mean = 10 seconds.
|
| + const float kMeanMs = 10000.0f;
|
| + Random random(0x12345678);
|
| +
|
| + std::vector<int64_t> tcp_starting_times_ms;
|
| +
|
| + // Two TCP Flows are initialized simultaneosly at t=0 seconds.
|
| + for (int i = 0; i < 2; ++i, --num_files) {
|
| + tcp_starting_times_ms.push_back(0);
|
| + }
|
| +
|
| + // Other TCP Flows are initialized in an OFF state.
|
| + while (num_files-- > 0) {
|
| + tcp_starting_times_ms.push_back(
|
| + static_cast<int64_t>(random.Exponential(1.0f / kMeanMs)));
|
| + }
|
| +
|
| + return tcp_starting_times_ms;
|
| +}
|
| +
|
| } // namespace bwe
|
| } // namespace testing
|
| } // namespace webrtc
|
|
|