Added implementation of three classes:

1) MaxBandwidthFilter
2) MinRttFilter
3) CongestionWindow

Added unit-tests for those classes.

BUG=webrtc:7713

Review-Url: https://codereview.webrtc.org/2966403002
Cr-Commit-Position: refs/heads/master@{#19067}
This commit is contained in:
gnish
2017-07-18 02:50:22 -07:00
committed by Commit Bot
parent 3124cc6921
commit 157cbbd3a7
11 changed files with 359 additions and 48 deletions

View File

@ -74,6 +74,7 @@ if (rtc_include_tests) {
"test/bwe_test_logging.h",
"test/estimators/bbr.cc",
"test/estimators/bbr.h",
"test/estimators/congestion_window.cc",
"test/estimators/congestion_window.h",
"test/estimators/max_bandwidth_filter.cc",
"test/estimators/max_bandwidth_filter.h",
@ -177,6 +178,9 @@ if (rtc_include_tests) {
"send_time_history_unittest.cc",
"test/bwe_test_framework_unittest.cc",
"test/bwe_unittest.cc",
"test/estimators/congestion_window_unittest.cc",
"test/estimators/max_bandwidth_filter_unittest.cc",
"test/estimators/min_rtt_filter_unittest.cc",
"test/estimators/nada_unittest.cc",
"test/metric_recorder_unittest.cc",
]

View File

@ -25,7 +25,7 @@ const float kHighGain = 2.885f;
// time.
const float kDrainGain = 1 / kHighGain;
// kStartupGrowthTarget and kMaxRoundsWithoutGrowth are chosen from
// experiments,according to design document.
// experiments, according to the design document.
const float kStartupGrowthTarget = 1.25f;
const int kMaxRoundsWithoutGrowth = 3;
} // namespace
@ -68,23 +68,23 @@ void BbrBweSender::GiveFeedback(const FeedbackPacket& feedback) {
full_bandwidth_reached_ = max_bandwidth_filter_->FullBandwidthReached(
kStartupGrowthTarget, kMaxRoundsWithoutGrowth);
}
int now = clock_->TimeInMilliseconds();
int now_ms = clock_->TimeInMilliseconds();
switch (mode_) {
break;
case STARTUP:
TryExitingStartup();
break;
case DRAIN:
TryExitingDrain(now);
TryExitingDrain(now_ms);
break;
case PROBE_BW:
TryUpdatingCyclePhase(now);
TryUpdatingCyclePhase(now_ms);
break;
case PROBE_RTT:
TryExitingProbeRtt(now);
TryExitingProbeRtt(now_ms);
break;
}
TryEnteringProbeRtt(now);
TryEnteringProbeRtt(now_ms);
// TODO(gnish): implement functions updating congestion window and pacing rate
// controllers.
}
@ -107,14 +107,14 @@ void BbrBweSender::TryExitingStartup() {
}
}
void BbrBweSender::TryExitingDrain(int64_t now) {}
void BbrBweSender::TryExitingDrain(int64_t now_ms) {}
void BbrBweSender::EnterProbeBw(int64_t now) {}
void BbrBweSender::EnterProbeBw(int64_t now_ms) {}
void BbrBweSender::TryUpdatingCyclePhase(int64_t now) {}
void BbrBweSender::TryUpdatingCyclePhase(int64_t now_ms) {}
void BbrBweSender::TryEnteringProbeRtt(int64_t now) {}
void BbrBweSender::TryExitingProbeRtt(int64_t now) {}
void BbrBweSender::TryEnteringProbeRtt(int64_t now_ms) {}
void BbrBweSender::TryExitingProbeRtt(int64_t now_ms) {}
int64_t BbrBweSender::TimeUntilNextProcess() {
return 100;

View File

@ -57,12 +57,12 @@ class BbrBweSender : public BweSender {
void EnterStartup();
bool UpdateBandwidthAndMinRtt();
void TryExitingStartup();
void TryExitingDrain(int64_t now);
void EnterProbeBw(int64_t now);
void EnterProbeRtt(int64_t now);
void TryUpdatingCyclePhase(int64_t now);
void TryEnteringProbeRtt(int64_t now);
void TryExitingProbeRtt(int64_t now);
void TryExitingDrain(int64_t now_ms);
void EnterProbeBw(int64_t now_ms);
void EnterProbeRtt(int64_t now_ms);
void TryUpdatingCyclePhase(int64_t now_ms);
void TryEnteringProbeRtt(int64_t now_ms);
void TryExitingProbeRtt(int64_t now_ms);
Clock* const clock_;
Mode mode_;
std::unique_ptr<MaxBandwidthFilter> max_bandwidth_filter_;

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2017 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 "webrtc/modules/remote_bitrate_estimator/test/estimators/congestion_window.h"
#include <algorithm>
#include "webrtc/modules/remote_bitrate_estimator/test/estimators/bbr.h"
namespace webrtc {
namespace testing {
namespace bwe {
namespace {
// kStartingCongestionWindow is used to set congestion window when bandwidth
// delay product is equal to zero, so that we don't set window to zero as well.
// Chosen randomly by me, because this value shouldn't make any significant
// difference, as bandwidth delay product is more than zero almost every time.
const int kStartingCongestionWindow = 6000;
// Size of congestion window while in PROBE_RTT mode, suggested by BBR's source
// code of QUIC's implementation.
const int kMinimumCongestionWindow = 5840;
} // namespace
CongestionWindow::CongestionWindow() : data_inflight_bytes_(0) {}
CongestionWindow::~CongestionWindow() {}
int CongestionWindow::GetCongestionWindow(
BbrBweSender::Mode mode,
int64_t bandwidth_estimate_bytes_per_ms,
int64_t min_rtt_ms,
float gain) {
if (mode == BbrBweSender::PROBE_RTT)
return kMinimumCongestionWindow;
return GetTargetCongestionWindow(bandwidth_estimate_bytes_per_ms, min_rtt_ms,
gain);
}
void CongestionWindow::PacketSent(size_t sent_packet_size_bytes) {
data_inflight_bytes_ += sent_packet_size_bytes;
}
void CongestionWindow::AckReceived(size_t received_packet_size_bytes) {
data_inflight_bytes_ -= received_packet_size_bytes;
}
int CongestionWindow::GetTargetCongestionWindow(
int64_t bandwidth_estimate_bytes_per_ms,
int64_t min_rtt_ms,
float gain) {
int bdp = min_rtt_ms * bandwidth_estimate_bytes_per_ms;
int congestion_window = bdp * gain;
// Congestion window could be zero in rare cases, when either no bandwidth
// estimate is available, or path's min_rtt value is zero.
if (!congestion_window)
congestion_window = gain * kStartingCongestionWindow;
return std::max(congestion_window, kMinimumCongestionWindow);
}
} // namespace bwe
} // namespace testing
} // namespace webrtc

View File

@ -12,22 +12,33 @@
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_ESTIMATORS_CONGESTION_WINDOW_H_
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_ESTIMATORS_CONGESTION_WINDOW_H_
#include "webrtc/modules/remote_bitrate_estimator/test/estimators/bbr.h"
namespace webrtc {
namespace testing {
namespace bwe {
class CongestionWindow {
public:
void set_gain(float gain);
size_t data_inflight();
int64_t GetCongestionWindow();
CongestionWindow();
~CongestionWindow();
int GetCongestionWindow(BbrBweSender::Mode mode,
int64_t bandwidth_estimate,
int64_t min_rtt,
float gain);
int GetTargetCongestionWindow(int64_t bandwidth_estimate,
int64_t min_rtt,
float gain);
// Packet sent from sender, meaning it is inflight until we receive it and we
// should add packet's size to data_inflight.
void PacketSent(size_t sent_packet_size);
// Packet sent from sender, meaning it is inflight
// until we receive it and we should add packet's size to data_inflight.
void PacketSent();
// Ack was received by sender, meaning packet is no longer inflight.
void AckReceived(size_t received_packet_size);
// Ack was received by sender, meaning
// packet is no longer inflight.
void AckReceived();
size_t data_inflight() { return data_inflight_bytes_; }
private:
size_t data_inflight_bytes_;
};
} // namespace bwe
} // namespace testing

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2017 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 "webrtc/modules/remote_bitrate_estimator/test/estimators/congestion_window.h"
#include "webrtc/modules/remote_bitrate_estimator/test/estimators/bbr.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace testing {
namespace bwe {
namespace {
// These are the same values used in CongestionWindow class.
const int64_t kStartingCongestionWindow = 6000;
const int64_t kMinimumCongestionWindow = 5840;
} // namespace
TEST(CongestionWindowTest, InitializationCheck) {
CongestionWindow congestion_window;
congestion_window.PacketSent(0);
EXPECT_EQ(congestion_window.data_inflight(), 0u);
congestion_window.AckReceived(0);
EXPECT_EQ(congestion_window.data_inflight(), 0u);
}
TEST(CongestionWindowTest, DataInflight) {
CongestionWindow congestion_window;
congestion_window.PacketSent(13);
EXPECT_EQ(congestion_window.data_inflight(), 13u);
congestion_window.AckReceived(12);
EXPECT_EQ(congestion_window.data_inflight(), 1u);
congestion_window.PacketSent(10);
congestion_window.PacketSent(9);
EXPECT_EQ(congestion_window.data_inflight(), 20u);
congestion_window.AckReceived(20);
EXPECT_EQ(congestion_window.data_inflight(), 0u);
}
TEST(CongestionWindowTest, ZeroBandwidthDelayProduct) {
CongestionWindow congestion_window;
int64_t target_congestion_window =
congestion_window.GetTargetCongestionWindow(100, 0, 2.885f);
EXPECT_EQ(target_congestion_window, 2.885f * kStartingCongestionWindow);
}
TEST(CongestionWindowTest, BelowMinimumTargetCongestionWindow) {
CongestionWindow congestion_window;
int64_t target_congestion_window =
congestion_window.GetTargetCongestionWindow(100, 2, 2.885f);
EXPECT_EQ(target_congestion_window, kMinimumCongestionWindow);
}
TEST(CongestionWindowTest, AboveMinimumTargetCongestionWindow) {
CongestionWindow congestion_window;
int64_t target_congestion_window =
congestion_window.GetTargetCongestionWindow(100000, 2, 2.885f);
EXPECT_EQ(target_congestion_window, 577000);
}
TEST(CongestionWindowTest, MinimumCongestionWindow) {
CongestionWindow congestion_window;
int64_t cwnd = congestion_window.GetCongestionWindow(BbrBweSender::PROBE_RTT,
100, 100, 2.885f);
EXPECT_EQ(cwnd, kMinimumCongestionWindow);
}
TEST(CongestionWindowTest, CalculateCongestionWindow) {
CongestionWindow congestion_window;
int64_t cwnd = congestion_window.GetCongestionWindow(BbrBweSender::STARTUP,
100, 100, 2.885f);
EXPECT_EQ(cwnd, 28850);
}
} // namespace bwe
} // namespace testing
} // namespace webrtc

View File

@ -14,24 +14,39 @@
namespace webrtc {
namespace testing {
namespace bwe {
MaxBandwidthFilter::MaxBandwidthFilter() {}
MaxBandwidthFilter::MaxBandwidthFilter()
: bandwidth_last_round_bytes_per_ms_(0),
round_bandwidth_updated_(0),
max_bandwidth_estimate_bytes_per_ms_(0),
rounds_without_growth_(0) {}
MaxBandwidthFilter::~MaxBandwidthFilter() {}
// Rounds are units for packets rtt_time, after packet has been acknowledged,
// one round has passed from its send time.
void MaxBandwidthFilter::AddBandwidthSample(int64_t sample_bytes_per_ms,
int64_t round,
size_t filter_size_round) {
if (round - round_bandwidth_updated_ >= filter_size_round ||
sample_bytes_per_ms >= max_bandwidth_estimate_bytes_per_ms_) {
max_bandwidth_estimate_bytes_per_ms_ = sample_bytes_per_ms;
round_bandwidth_updated_ = round;
}
}
bool MaxBandwidthFilter::FullBandwidthReached(float growth_target,
int max_rounds_without_growth) {
// Minimal bandwidth necessary to assume that better bandwidth can still be
// found and full bandwidth is not reached.
int64_t minimal_bandwidth = bandwidth_last_round_ * growth_target;
if (max_bandwidth_estimate_ >= minimal_bandwidth) {
bandwidth_last_round_ = max_bandwidth_estimate_;
int64_t minimal_bandwidth =
bandwidth_last_round_bytes_per_ms_ * growth_target;
if (max_bandwidth_estimate_bytes_per_ms_ >= minimal_bandwidth) {
bandwidth_last_round_bytes_per_ms_ = max_bandwidth_estimate_bytes_per_ms_;
rounds_without_growth_ = 0;
return false;
}
rounds_without_growth_++;
if (rounds_without_growth_ >= max_rounds_without_growth)
return true;
return false;
return rounds_without_growth_ >= max_rounds_without_growth;
}
} // namespace bwe
} // namespace testing

View File

@ -12,6 +12,7 @@
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_ESTIMATORS_MAX_BANDWIDTH_FILTER_H_
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_ESTIMATORS_MAX_BANDWIDTH_FILTER_H_
#include <cstddef>
#include <cstdint>
namespace webrtc {
@ -22,21 +23,22 @@ class MaxBandwidthFilter {
MaxBandwidthFilter();
~MaxBandwidthFilter();
int64_t max_bandwidth_estimate() { return max_bandwidth_estimate_; }
int64_t max_bandwidth_estimate_bytes_per_ms() {
return max_bandwidth_estimate_bytes_per_ms_;
}
// Save bandwidth sample for the current round.
// We save bandwidth samples for past 10 rounds to
// provide better bandwidth estimate.
void AddBandwidthSample(int64_t sample, int64_t round);
// Save bandwidth sample for the current round. We save bandwidth samples for
// past 10 rounds to provide better bandwidth estimate.
void AddBandwidthSample(int64_t sample, int64_t round, size_t filter_size);
// Check if bandwidth has grown by certain multiplier for past x rounds,
// to decide whether or not full bandwidth was reached.
bool FullBandwidthReached(float growth_target, int max_rounds_without_growth);
private:
int64_t bandwidth_last_round_;
int64_t max_bandwidth_estimate_;
int64_t bandwidth_last_round_bytes_per_ms_;
uint64_t round_bandwidth_updated_;
int64_t max_bandwidth_estimate_bytes_per_ms_;
int64_t rounds_without_growth_;
};
} // namespace bwe

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2017 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 "webrtc/modules/remote_bitrate_estimator/test/estimators/max_bandwidth_filter.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace testing {
namespace bwe {
TEST(MaxBandwidthFilterTest, InitializationCheck) {
MaxBandwidthFilter max_bandwidth_filter;
EXPECT_EQ(max_bandwidth_filter.max_bandwidth_estimate_bytes_per_ms(), 0);
}
TEST(MaxBandwidthFilterTest, AddOneBandwidthSample) {
MaxBandwidthFilter max_bandwidth_filter;
max_bandwidth_filter.AddBandwidthSample(13, 4, 10);
EXPECT_EQ(max_bandwidth_filter.max_bandwidth_estimate_bytes_per_ms(), 13);
}
TEST(MaxBandwidthFilterTest, AddSeveralBandwidthSamples) {
MaxBandwidthFilter max_bandwidth_filter;
max_bandwidth_filter.AddBandwidthSample(10, 5, 10);
max_bandwidth_filter.AddBandwidthSample(13, 6, 10);
EXPECT_EQ(max_bandwidth_filter.max_bandwidth_estimate_bytes_per_ms(), 13);
}
TEST(MaxBandwidthFilterTest, SampleTimeOut) {
MaxBandwidthFilter max_bandwidth_filter;
max_bandwidth_filter.AddBandwidthSample(13, 5, 10);
max_bandwidth_filter.AddBandwidthSample(10, 15, 10);
EXPECT_EQ(max_bandwidth_filter.max_bandwidth_estimate_bytes_per_ms(), 10);
}
TEST(MaxBandwidthFilterTest, FullBandwidthReached) {
MaxBandwidthFilter max_bandwidth_filter;
max_bandwidth_filter.AddBandwidthSample(100, 1, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), false);
max_bandwidth_filter.AddBandwidthSample(110, 2, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), false);
max_bandwidth_filter.AddBandwidthSample(120, 3, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), false);
max_bandwidth_filter.AddBandwidthSample(124, 4, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), true);
}
TEST(MaxBandwidthFilterTest, FullBandwidthNotReached) {
MaxBandwidthFilter max_bandwidth_filter;
max_bandwidth_filter.AddBandwidthSample(100, 1, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), false);
max_bandwidth_filter.AddBandwidthSample(110, 2, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), false);
max_bandwidth_filter.AddBandwidthSample(120, 3, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), false);
max_bandwidth_filter.AddBandwidthSample(125, 4, 10);
EXPECT_EQ(max_bandwidth_filter.FullBandwidthReached(1.25f, 3), false);
}
} // namespace bwe
} // namespace testing
} // namespace webrtc

View File

@ -12,20 +12,37 @@
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_ESTIMATORS_MIN_RTT_FILTER_H_
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_ESTIMATORS_MIN_RTT_FILTER_H_
#include <cstdint>
#include <limits>
#include "webrtc/rtc_base/optional.h"
namespace webrtc {
namespace testing {
namespace bwe {
class MinRttFilter {
public:
MinRttFilter();
~MinRttFilter();
int64_t min_rtt();
void UpdateMinRtt(int64_t min_rtt);
MinRttFilter() {}
~MinRttFilter() {}
rtc::Optional<int64_t> min_rtt_ms() { return min_rtt_ms_; }
void add_rtt_sample(int64_t rtt_ms, int64_t now_ms) {
if (!min_rtt_ms_ || rtt_ms <= *min_rtt_ms_) {
min_rtt_ms_.emplace(rtt_ms);
discovery_time_ms_ = now_ms;
}
}
int64_t discovery_time() { return discovery_time_ms_; }
// Checks whether or not last discovered min_rtt value is older than x
// seconds.
bool MinRttExpired(int64_t now);
void set_min_rtt_discovery_time(int64_t discovery_time);
// milliseconds.
bool min_rtt_expired(int64_t now_ms, int64_t min_rtt_filter_window_size_ms) {
return now_ms - discovery_time_ms_ >= min_rtt_filter_window_size_ms;
}
private:
rtc::Optional<int64_t> min_rtt_ms_;
int64_t discovery_time_ms_ = 0;
};
} // namespace bwe
} // namespace testing

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2017 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 "webrtc/modules/remote_bitrate_estimator/test/estimators/min_rtt_filter.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace testing {
namespace bwe {
TEST(MinRttFilterTest, InitializationCheck) {
MinRttFilter min_rtt_filter;
EXPECT_FALSE(min_rtt_filter.min_rtt_ms());
EXPECT_EQ(min_rtt_filter.discovery_time(), 0);
}
TEST(MinRttFilterTest, AddRttSample) {
MinRttFilter min_rtt_filter;
min_rtt_filter.add_rtt_sample(120, 5);
EXPECT_EQ(min_rtt_filter.min_rtt_ms(), 120);
EXPECT_EQ(min_rtt_filter.discovery_time(), 5);
min_rtt_filter.add_rtt_sample(121, 6);
EXPECT_EQ(min_rtt_filter.discovery_time(), 5);
min_rtt_filter.add_rtt_sample(119, 7);
EXPECT_EQ(min_rtt_filter.discovery_time(), 7);
}
TEST(MinRttFilterTest, MinRttExpired) {
MinRttFilter min_rtt_filter;
min_rtt_filter.add_rtt_sample(120, 5);
EXPECT_EQ(min_rtt_filter.min_rtt_expired(10, 5), true);
EXPECT_EQ(min_rtt_filter.min_rtt_expired(9, 5), false);
}
} // namespace bwe
} // namespace testing
} // namespace webrtc