Using simulated time for GoogCC tests.

Bug: webrtc:10365
Change-Id: I482e544f1585fdb54dc49740ba81870104dd58a0
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/130509
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27468}
This commit is contained in:
Sebastian Jansson
2019-04-03 13:38:15 +02:00
committed by Commit Bot
parent 8f32b6c18c
commit ebd94f6df1
4 changed files with 219 additions and 267 deletions

View File

@ -254,36 +254,8 @@ if (rtc_include_tests) {
"//third_party/abseil-cpp/absl/memory",
]
}
rtc_source_set("goog_cc_slow_tests") {
testonly = true
sources = [
"goog_cc_network_control_slowtest.cc",
]
deps = [
":alr_detector",
":delay_based_bwe",
":estimators",
":goog_cc",
":probe_controller",
":pushback_controller",
"../../../api/transport:goog_cc",
"../../../api/transport:network_control",
"../../../api/transport:network_control_test",
"../../../api/transport:webrtc_key_value_config",
"../../../logging:mocks",
"../../../rtc_base:checks",
"../../../rtc_base:rtc_base_approved",
"../../../rtc_base/experiments:alr_experiment",
"../../../system_wrappers",
"../../../test:field_trial",
"../../../test:test_support",
"../../../test/scenario",
"../../pacing",
"../../remote_bitrate_estimator",
"../../rtp_rtcp:rtp_rtcp_format",
"//testing/gmock",
"//third_party/abseil-cpp/absl/memory",
]
# TODO(srte): Remove this target when dependency in root BUILD is gone.
rtc_source_set("goog_cc_slow_tests") {
}
}

View File

@ -1,235 +0,0 @@
/*
* Copyright (c) 2018 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 <queue>
#include "api/transport/goog_cc_factory.h"
#include "test/field_trial.h"
#include "test/gtest.h"
#include "test/scenario/scenario.h"
namespace webrtc {
namespace test {
namespace {
// Count dips from a constant high bandwidth level within a short window.
int CountBandwidthDips(std::queue<DataRate> bandwidth_history,
DataRate threshold) {
if (bandwidth_history.empty())
return true;
DataRate first = bandwidth_history.front();
bandwidth_history.pop();
int dips = 0;
bool state_high = true;
while (!bandwidth_history.empty()) {
if (bandwidth_history.front() + threshold < first && state_high) {
++dips;
state_high = false;
} else if (bandwidth_history.front() == first) {
state_high = true;
} else if (bandwidth_history.front() > first) {
// If this is toggling we will catch it later when front becomes first.
state_high = false;
}
bandwidth_history.pop();
}
return dips;
}
} // namespace
TEST(GoogCcNetworkControllerTest, MaintainsLowRateInSafeResetTrial) {
const DataRate kLinkCapacity = DataRate::kbps(200);
const DataRate kStartRate = DataRate::kbps(300);
ScopedFieldTrials trial("WebRTC-Bwe-SafeResetOnRouteChange/Enabled/");
Scenario s("googcc_unit/safe_reset_low", true);
auto* send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kLinkCapacity;
c->simulation.delay = TimeDelta::ms(10);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to stabilize.
s.RunFor(TimeDelta::ms(500));
EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 50);
s.ChangeRoute(route->forward(), {send_net});
// Allow new settings to propagate.
s.RunFor(TimeDelta::ms(100));
// Under the trial, the target should be unchanged for low rates.
EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 50);
}
TEST(GoogCcNetworkControllerTest, CutsHighRateInSafeResetTrial) {
const DataRate kLinkCapacity = DataRate::kbps(1000);
const DataRate kStartRate = DataRate::kbps(300);
ScopedFieldTrials trial("WebRTC-Bwe-SafeResetOnRouteChange/Enabled/");
Scenario s("googcc_unit/safe_reset_high_cut", true);
auto send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to stabilize.
s.RunFor(TimeDelta::ms(500));
EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 300);
s.ChangeRoute(route->forward(), {send_net});
// Allow new settings to propagate.
s.RunFor(TimeDelta::ms(50));
// Under the trial, the target should be reset from high values.
EXPECT_NEAR(client->send_bandwidth().kbps(), kStartRate.kbps(), 30);
}
TEST(GoogCcNetworkControllerTest, DetectsHighRateInSafeResetTrial) {
ScopedFieldTrials trial(
"WebRTC-Bwe-SafeResetOnRouteChange/Enabled,ack/"
"WebRTC-Bwe-ProbeRateFallback/Enabled/");
const DataRate kInitialLinkCapacity = DataRate::kbps(200);
const DataRate kNewLinkCapacity = DataRate::kbps(800);
const DataRate kStartRate = DataRate::kbps(300);
Scenario s("googcc_unit/safe_reset_high_detect", true);
auto* initial_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kInitialLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
auto* new_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kNewLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {initial_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to stabilize.
s.RunFor(TimeDelta::ms(1000));
EXPECT_NEAR(client->send_bandwidth().kbps(), kInitialLinkCapacity.kbps(), 50);
s.ChangeRoute(route->forward(), {new_net});
// Allow new settings to propagate, but not probes to be received.
s.RunFor(TimeDelta::ms(50));
// Under the field trial, the target rate should be unchanged since it's lower
// than the starting rate.
EXPECT_NEAR(client->send_bandwidth().kbps(), kInitialLinkCapacity.kbps(), 50);
// However, probing should have made us detect the higher rate.
s.RunFor(TimeDelta::ms(2000));
EXPECT_GT(client->send_bandwidth().kbps(), kNewLinkCapacity.kbps() - 300);
}
TEST(GoogCcNetworkControllerTest,
TargetRateReducedOnPacingBufferBuildupInTrial) {
// Configure strict pacing to ensure build-up.
ScopedFieldTrials trial(
"WebRTC-CongestionWindowPushback/Enabled/WebRTC-CwndExperiment/"
"Enabled-100/WebRTC-Video-Pacing/factor:1.0/"
"WebRTC-AddPacingToCongestionWindowPushback/Enabled/");
const DataRate kLinkCapacity = DataRate::kbps(1000);
const DataRate kStartRate = DataRate::kbps(1000);
Scenario s("googcc_unit/pacing_buffer_buildup", true);
auto* net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
// TODO(srte): replace with SimulatedTimeClient when it supports pacing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow some time for the buffer to build up.
s.RunFor(TimeDelta::seconds(5));
// Without trial, pacer delay reaches ~250 ms.
EXPECT_LT(client->GetStats().pacer_delay_ms, 150);
}
TEST(GoogCcNetworkControllerTest, NoBandwidthTogglingInLossControlTrial) {
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
Scenario s("googcc_unit/no_toggling", true);
auto* send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = DataRate::kbps(2000);
c->simulation.loss_rate = 0.2;
c->simulation.delay = TimeDelta::ms(10);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = DataRate::kbps(300);
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to initialize.
s.RunFor(TimeDelta::ms(250));
std::queue<DataRate> bandwidth_history;
const TimeDelta step = TimeDelta::ms(50);
for (TimeDelta time = TimeDelta::Zero(); time < TimeDelta::ms(2000);
time += step) {
s.RunFor(step);
const TimeDelta window = TimeDelta::ms(500);
if (bandwidth_history.size() >= window / step)
bandwidth_history.pop();
bandwidth_history.push(client->send_bandwidth());
EXPECT_LT(CountBandwidthDips(bandwidth_history, DataRate::kbps(100)), 2);
}
}
TEST(GoogCcNetworkControllerTest, NoRttBackoffCollapseWhenVideoStops) {
ScopedFieldTrials trial("WebRTC-Bwe-MaxRttLimit/limit:2s/");
Scenario s("googcc_unit/rttbackoff_video_stop", true);
auto* send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = DataRate::kbps(2000);
c->simulation.delay = TimeDelta::ms(100);
});
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = DataRate::kbps(1000);
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
auto* video = s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to initialize, then stop video.
s.RunFor(TimeDelta::seconds(1));
video->send()->Stop();
s.RunFor(TimeDelta::seconds(4));
EXPECT_GT(client->send_bandwidth().kbps(), 1000);
}
} // namespace test
} // namespace webrtc

View File

@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <queue>
#include "api/transport/goog_cc_factory.h"
#include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
#include "test/field_trial.h"
@ -23,6 +25,30 @@ using testing::_;
namespace webrtc {
namespace test {
namespace {
// Count dips from a constant high bandwidth level within a short window.
int CountBandwidthDips(std::queue<DataRate> bandwidth_history,
DataRate threshold) {
if (bandwidth_history.empty())
return true;
DataRate first = bandwidth_history.front();
bandwidth_history.pop();
int dips = 0;
bool state_high = true;
while (!bandwidth_history.empty()) {
if (bandwidth_history.front() + threshold < first && state_high) {
++dips;
state_high = false;
} else if (bandwidth_history.front() == first) {
state_high = true;
} else if (bandwidth_history.front() > first) {
// If this is toggling we will catch it later when front becomes first.
state_high = false;
}
bandwidth_history.pop();
}
return dips;
}
const uint32_t kInitialBitrateKbps = 60;
const DataRate kInitialBitrate = DataRate::kbps(kInitialBitrateKbps);
@ -505,5 +531,192 @@ TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) {
EXPECT_LT(client->target_rate_kbps(), 3000);
}
TEST_F(GoogCcNetworkControllerTest, MaintainsLowRateInSafeResetTrial) {
const DataRate kLinkCapacity = DataRate::kbps(200);
const DataRate kStartRate = DataRate::kbps(300);
ScopedFieldTrials trial("WebRTC-Bwe-SafeResetOnRouteChange/Enabled/");
Scenario s("googcc_unit/safe_reset_low");
auto* send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kLinkCapacity;
c->simulation.delay = TimeDelta::ms(10);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to stabilize.
s.RunFor(TimeDelta::ms(500));
EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 50);
s.ChangeRoute(route->forward(), {send_net});
// Allow new settings to propagate.
s.RunFor(TimeDelta::ms(100));
// Under the trial, the target should be unchanged for low rates.
EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 50);
}
TEST_F(GoogCcNetworkControllerTest, CutsHighRateInSafeResetTrial) {
const DataRate kLinkCapacity = DataRate::kbps(1000);
const DataRate kStartRate = DataRate::kbps(300);
ScopedFieldTrials trial("WebRTC-Bwe-SafeResetOnRouteChange/Enabled/");
Scenario s("googcc_unit/safe_reset_high_cut");
auto send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to stabilize.
s.RunFor(TimeDelta::ms(500));
EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 300);
s.ChangeRoute(route->forward(), {send_net});
// Allow new settings to propagate.
s.RunFor(TimeDelta::ms(50));
// Under the trial, the target should be reset from high values.
EXPECT_NEAR(client->send_bandwidth().kbps(), kStartRate.kbps(), 30);
}
TEST_F(GoogCcNetworkControllerTest, DetectsHighRateInSafeResetTrial) {
ScopedFieldTrials trial(
"WebRTC-Bwe-SafeResetOnRouteChange/Enabled,ack/"
"WebRTC-Bwe-ProbeRateFallback/Enabled/");
const DataRate kInitialLinkCapacity = DataRate::kbps(200);
const DataRate kNewLinkCapacity = DataRate::kbps(800);
const DataRate kStartRate = DataRate::kbps(300);
Scenario s("googcc_unit/safe_reset_high_detect");
auto* initial_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kInitialLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
auto* new_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kNewLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {initial_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to stabilize.
s.RunFor(TimeDelta::ms(1000));
EXPECT_NEAR(client->send_bandwidth().kbps(), kInitialLinkCapacity.kbps(), 50);
s.ChangeRoute(route->forward(), {new_net});
// Allow new settings to propagate, but not probes to be received.
s.RunFor(TimeDelta::ms(50));
// Under the field trial, the target rate should be unchanged since it's lower
// than the starting rate.
EXPECT_NEAR(client->send_bandwidth().kbps(), kInitialLinkCapacity.kbps(), 50);
// However, probing should have made us detect the higher rate.
s.RunFor(TimeDelta::ms(2000));
EXPECT_GT(client->send_bandwidth().kbps(), kNewLinkCapacity.kbps() - 300);
}
TEST_F(GoogCcNetworkControllerTest,
TargetRateReducedOnPacingBufferBuildupInTrial) {
// Configure strict pacing to ensure build-up.
ScopedFieldTrials trial(
"WebRTC-CongestionWindowPushback/Enabled/WebRTC-CwndExperiment/"
"Enabled-100/WebRTC-Video-Pacing/factor:1.0/"
"WebRTC-AddPacingToCongestionWindowPushback/Enabled/");
const DataRate kLinkCapacity = DataRate::kbps(1000);
const DataRate kStartRate = DataRate::kbps(1000);
Scenario s("googcc_unit/pacing_buffer_buildup");
auto* net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = kLinkCapacity;
c->simulation.delay = TimeDelta::ms(50);
});
// TODO(srte): replace with SimulatedTimeClient when it supports pacing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = kStartRate;
});
auto* route = s.CreateRoutes(client, {net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow some time for the buffer to build up.
s.RunFor(TimeDelta::seconds(5));
// Without trial, pacer delay reaches ~250 ms.
EXPECT_LT(client->GetStats().pacer_delay_ms, 150);
}
TEST_F(GoogCcNetworkControllerTest, NoBandwidthTogglingInLossControlTrial) {
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
Scenario s("googcc_unit/no_toggling");
auto* send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = DataRate::kbps(2000);
c->simulation.loss_rate = 0.2;
c->simulation.delay = TimeDelta::ms(10);
});
// TODO(srte): replace with SimulatedTimeClient when it supports probing.
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = DataRate::kbps(300);
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to initialize.
s.RunFor(TimeDelta::ms(250));
std::queue<DataRate> bandwidth_history;
const TimeDelta step = TimeDelta::ms(50);
for (TimeDelta time = TimeDelta::Zero(); time < TimeDelta::ms(2000);
time += step) {
s.RunFor(step);
const TimeDelta window = TimeDelta::ms(500);
if (bandwidth_history.size() >= window / step)
bandwidth_history.pop();
bandwidth_history.push(client->send_bandwidth());
EXPECT_LT(CountBandwidthDips(bandwidth_history, DataRate::kbps(100)), 2);
}
}
TEST_F(GoogCcNetworkControllerTest, NoRttBackoffCollapseWhenVideoStops) {
ScopedFieldTrials trial("WebRTC-Bwe-MaxRttLimit/limit:2s/");
Scenario s("googcc_unit/rttbackoff_video_stop");
auto* send_net = s.CreateSimulationNode([&](NetworkNodeConfig* c) {
c->simulation.bandwidth = DataRate::kbps(2000);
c->simulation.delay = TimeDelta::ms(100);
});
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.cc = TransportControllerConfig::CongestionController::kGoogCc;
c->transport.rates.start_rate = DataRate::kbps(1000);
});
auto* route = s.CreateRoutes(client, {send_net},
s.CreateClient("return", CallClientConfig()),
{s.CreateSimulationNode(NetworkNodeConfig())});
auto* video = s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to initialize, then stop video.
s.RunFor(TimeDelta::seconds(1));
video->send()->Stop();
s.RunFor(TimeDelta::seconds(4));
EXPECT_GT(client->send_bandwidth().kbps(), 1000);
}
} // namespace test
} // namespace webrtc

View File

@ -56,9 +56,11 @@ std::unique_ptr<TimeController> CreateTimeController(bool real_time) {
}
Scenario::Scenario()
: Scenario(std::unique_ptr<LogWriterFactoryInterface>(), true) {}
: Scenario(std::unique_ptr<LogWriterFactoryInterface>(),
/*real_time=*/false) {}
Scenario::Scenario(std::string file_name) : Scenario(file_name, true) {}
Scenario::Scenario(std::string file_name)
: Scenario(file_name, /*real_time=*/false) {}
Scenario::Scenario(std::string file_name, bool real_time)
: Scenario(GetScenarioLogManager(file_name), real_time) {}