Adding DataTransferTracker class for BBR.
This class is completely new and tracks data transfer in a slightly different way compared to the BBR implementation in QUIC. The fundamental change is that receive time is used rather than packet index to identify the packets over which data rates should be calculated. This is part of a series of CLs adding a network controller based on the BBR congestion control method. The code is based on the QUIC BBR implementation in Chromium. Bug: webrtc:8415 Change-Id: I9d1f12634073ac89c4d542f965e3677a89a1526c Reviewed-on: https://webrtc-review.googlesource.com/63680 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Philip Eliasson <philipel@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22589}
This commit is contained in:

committed by
Commit Bot

parent
2bd41f9e0e
commit
883f470d60
@ -8,6 +8,17 @@
|
||||
|
||||
import("../../../webrtc.gni")
|
||||
|
||||
rtc_source_set("data_transfer_tracker") {
|
||||
sources = [
|
||||
"data_transfer_tracker.cc",
|
||||
"data_transfer_tracker.h",
|
||||
]
|
||||
deps = [
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../network_control",
|
||||
]
|
||||
}
|
||||
rtc_source_set("rtt_stats") {
|
||||
sources = [
|
||||
"rtt_stats.cc",
|
||||
@ -18,14 +29,15 @@ rtc_source_set("rtt_stats") {
|
||||
"../network_control",
|
||||
]
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
rtc_source_set("bbr_unittests") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"data_transfer_tracker_unittest.cc",
|
||||
"rtt_stats_unittest.cc",
|
||||
]
|
||||
deps = [
|
||||
":data_transfer_tracker",
|
||||
":rtt_stats",
|
||||
"../../../test:test_support",
|
||||
"../network_control",
|
||||
|
85
modules/congestion_controller/bbr/data_transfer_tracker.cc
Normal file
85
modules/congestion_controller/bbr/data_transfer_tracker.cc
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 "modules/congestion_controller/bbr/data_transfer_tracker.h"
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace bbr {
|
||||
|
||||
DataTransferTracker::DataTransferTracker() {}
|
||||
|
||||
DataTransferTracker::~DataTransferTracker() {}
|
||||
|
||||
void DataTransferTracker::AddSample(DataSize size_delta,
|
||||
Timestamp send_time,
|
||||
Timestamp ack_time) {
|
||||
size_sum_ += size_delta;
|
||||
if (!samples_.empty()) {
|
||||
RTC_DCHECK_GE(send_time, samples_.back().send_time);
|
||||
RTC_DCHECK_GE(ack_time, samples_.back().ack_time);
|
||||
}
|
||||
if (!samples_.empty() && ack_time == samples_.back().ack_time) {
|
||||
samples_.back().send_time = send_time;
|
||||
samples_.back().size_sum = size_sum_;
|
||||
} else {
|
||||
Sample new_sample;
|
||||
new_sample.ack_time = ack_time;
|
||||
new_sample.send_time = send_time;
|
||||
new_sample.size_delta = size_delta;
|
||||
new_sample.size_sum = size_sum_;
|
||||
samples_.push_back(new_sample);
|
||||
}
|
||||
}
|
||||
|
||||
void DataTransferTracker::ClearOldSamples(Timestamp excluding_end) {
|
||||
while (!samples_.empty() && samples_.front().ack_time < excluding_end) {
|
||||
samples_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
DataTransferTracker::Result DataTransferTracker::GetRatesByAckTime(
|
||||
Timestamp covered_start,
|
||||
Timestamp including_end) {
|
||||
Result res;
|
||||
// Last sample before covered_start.
|
||||
const Sample* window_begin = nullptr;
|
||||
// Sample at end time or first sample after end time-
|
||||
const Sample* window_end = nullptr;
|
||||
// To handle the case when the first sample is after covered_start.
|
||||
if (samples_.front().ack_time < including_end)
|
||||
window_begin = &samples_.front();
|
||||
// To handle the case when the last sample is before including_end.
|
||||
if (samples_.back().ack_time > covered_start)
|
||||
window_end = &samples_.back();
|
||||
for (const auto& sample : samples_) {
|
||||
if (sample.ack_time < covered_start) {
|
||||
window_begin = &sample;
|
||||
} else if (sample.ack_time >= including_end) {
|
||||
window_end = &sample;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window_begin != nullptr && window_end != nullptr) {
|
||||
res.acked_data = window_end->size_sum - window_begin->size_sum;
|
||||
res.send_timespan = window_end->send_time - window_begin->send_time;
|
||||
res.ack_timespan = window_end->ack_time - window_begin->ack_time;
|
||||
} else {
|
||||
res.acked_data = DataSize::Zero();
|
||||
res.ack_timespan = including_end - covered_start;
|
||||
res.send_timespan = TimeDelta::Zero();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace bbr
|
||||
} // namespace webrtc
|
47
modules/congestion_controller/bbr/data_transfer_tracker.h
Normal file
47
modules/congestion_controller/bbr/data_transfer_tracker.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MODULES_CONGESTION_CONTROLLER_BBR_DATA_TRANSFER_TRACKER_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_BBR_DATA_TRANSFER_TRACKER_H_
|
||||
|
||||
#include <deque>
|
||||
#include "modules/congestion_controller/network_control/include/network_units.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace bbr {
|
||||
class DataTransferTracker {
|
||||
public:
|
||||
struct Result {
|
||||
TimeDelta ack_timespan;
|
||||
TimeDelta send_timespan;
|
||||
DataSize acked_data;
|
||||
};
|
||||
DataTransferTracker();
|
||||
~DataTransferTracker();
|
||||
void AddSample(DataSize size_delta, Timestamp send_time, Timestamp ack_time);
|
||||
void ClearOldSamples(Timestamp excluding_end);
|
||||
|
||||
// Get the average data rate in the window that starts with the last ack which
|
||||
// comes before covered_start and ends at the first ack that comes after or at
|
||||
// including_end.
|
||||
Result GetRatesByAckTime(Timestamp covered_start, Timestamp including_end);
|
||||
|
||||
private:
|
||||
struct Sample {
|
||||
Timestamp ack_time;
|
||||
Timestamp send_time;
|
||||
DataSize size_delta;
|
||||
DataSize size_sum;
|
||||
};
|
||||
std::deque<Sample> samples_;
|
||||
DataSize size_sum_ = DataSize::Zero();
|
||||
};
|
||||
} // namespace bbr
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_BBR_DATA_TRANSFER_TRACKER_H_
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 "modules/congestion_controller/bbr/data_transfer_tracker.h"
|
||||
#include "modules/congestion_controller/network_control/include/network_units.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace bbr {
|
||||
namespace test {
|
||||
namespace {
|
||||
struct ResultForTest {
|
||||
int64_t ack_span_ms;
|
||||
int64_t send_span_ms;
|
||||
int64_t acked_bytes;
|
||||
};
|
||||
class DataTransferTrackerForTest : public DataTransferTracker {
|
||||
public:
|
||||
void AddSample(int bytes, int send_time_ms, int ack_time_ms) {
|
||||
DataTransferTracker::AddSample(DataSize::bytes(bytes),
|
||||
Timestamp::ms(send_time_ms),
|
||||
Timestamp::ms(ack_time_ms));
|
||||
}
|
||||
|
||||
void ClearOldSamples(int excluding_end_ms) {
|
||||
DataTransferTracker::ClearOldSamples(Timestamp::ms(excluding_end_ms));
|
||||
}
|
||||
ResultForTest GetRatesByAckTime(int covered_start_ms, int including_end_ms) {
|
||||
auto result = DataTransferTracker::GetRatesByAckTime(
|
||||
Timestamp::ms(covered_start_ms), Timestamp::ms(including_end_ms));
|
||||
return ResultForTest{result.ack_timespan.ms(), result.send_timespan.ms(),
|
||||
result.acked_data.bytes()};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DataTransferTrackerTest, TracksData) {
|
||||
DataTransferTrackerForTest calc;
|
||||
// Since we dont have any previous reference for the first packet, it won't be
|
||||
// counted.
|
||||
calc.AddSample(5555, 100000, 100100);
|
||||
calc.AddSample(1000, 100020, 100120);
|
||||
calc.AddSample(1000, 100040, 100140);
|
||||
calc.AddSample(1000, 100060, 100160);
|
||||
|
||||
auto result = calc.GetRatesByAckTime(100000, 100200);
|
||||
EXPECT_EQ(result.acked_bytes, 3000);
|
||||
EXPECT_EQ(result.ack_span_ms, 60);
|
||||
EXPECT_EQ(result.send_span_ms, 60);
|
||||
}
|
||||
|
||||
TEST(DataTransferTrackerTest, CoversStartTime) {
|
||||
DataTransferTrackerForTest calc;
|
||||
calc.AddSample(5555, 100000, 100100);
|
||||
calc.AddSample(1000, 100020, 100120);
|
||||
calc.AddSample(1000, 100040, 100140);
|
||||
calc.AddSample(1000, 100060, 100160);
|
||||
calc.AddSample(1000, 100080, 100180);
|
||||
|
||||
auto result = calc.GetRatesByAckTime(100140, 100200);
|
||||
EXPECT_EQ(result.acked_bytes, 3000);
|
||||
EXPECT_EQ(result.ack_span_ms, 60);
|
||||
EXPECT_EQ(result.send_span_ms, 60);
|
||||
}
|
||||
|
||||
TEST(DataTransferTrackerTest, IncludesEndExcludesPastEnd) {
|
||||
DataTransferTrackerForTest calc;
|
||||
calc.AddSample(5555, 100000, 100100);
|
||||
calc.AddSample(1000, 100020, 100120);
|
||||
calc.AddSample(1000, 100040, 100140);
|
||||
calc.AddSample(1000, 100060, 100160);
|
||||
calc.AddSample(1000, 100080, 100180);
|
||||
|
||||
auto result = calc.GetRatesByAckTime(100120, 100160);
|
||||
EXPECT_EQ(result.acked_bytes, 3000);
|
||||
EXPECT_EQ(result.ack_span_ms, 60);
|
||||
EXPECT_EQ(result.send_span_ms, 60);
|
||||
}
|
||||
|
||||
TEST(DataTransferTrackerTest, AccumulatesDuplicates) {
|
||||
DataTransferTrackerForTest calc;
|
||||
calc.AddSample(5555, 100000, 100100);
|
||||
// Two packets at same time, should be accumulated.
|
||||
calc.AddSample(1000, 100020, 100120);
|
||||
calc.AddSample(1000, 100020, 100120);
|
||||
calc.AddSample(1000, 100060, 100160);
|
||||
// Two packets at same time, should be accumulated.
|
||||
calc.AddSample(1000, 100100, 100200);
|
||||
calc.AddSample(1000, 100100, 100200);
|
||||
calc.AddSample(1000, 100120, 100220);
|
||||
|
||||
auto result = calc.GetRatesByAckTime(100120, 100200);
|
||||
EXPECT_EQ(result.acked_bytes, 5000);
|
||||
EXPECT_EQ(result.ack_span_ms, 100);
|
||||
EXPECT_EQ(result.send_span_ms, 100);
|
||||
}
|
||||
|
||||
TEST(DataTransferTrackerTest, RemovesOldData) {
|
||||
DataTransferTrackerForTest calc;
|
||||
calc.AddSample(5555, 100000, 100100);
|
||||
calc.AddSample(1000, 100020, 100120);
|
||||
calc.AddSample(1000, 100040, 100140);
|
||||
calc.AddSample(1000, 100060, 100160);
|
||||
calc.AddSample(1000, 100080, 100180);
|
||||
{
|
||||
auto result = calc.GetRatesByAckTime(100120, 100200);
|
||||
EXPECT_EQ(result.acked_bytes, 4000);
|
||||
EXPECT_EQ(result.ack_span_ms, 80);
|
||||
EXPECT_EQ(result.send_span_ms, 80);
|
||||
}
|
||||
// Note that this operation means that the packet acked at 100140 will not be
|
||||
// counted any more, just used as time reference.
|
||||
calc.ClearOldSamples(100140);
|
||||
{
|
||||
auto result = calc.GetRatesByAckTime(100120, 100200);
|
||||
EXPECT_EQ(result.acked_bytes, 2000);
|
||||
EXPECT_EQ(result.ack_span_ms, 40);
|
||||
EXPECT_EQ(result.send_span_ms, 40);
|
||||
}
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace bbr
|
||||
} // namespace webrtc
|
Reference in New Issue
Block a user