Adds utility function for PCC.

Bug: webrtc:9434
Change-Id: I840f39afdff1851d939005f82e64b23927bf455e
Reviewed-on: https://webrtc-review.googlesource.com/87146
Commit-Queue: Anastasia Koloskova <koloskova@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24369}
This commit is contained in:
Anastasia Koloskova 2018-08-21 16:12:31 +02:00 committed by Commit Bot
parent 9171e78ccd
commit ddbbf4601b
4 changed files with 279 additions and 0 deletions

View file

@ -30,16 +30,30 @@ rtc_static_library("rtt_tracker") {
]
}
rtc_static_library("utility_function") {
sources = [
"utility_function.cc",
"utility_function.h",
]
deps = [
":monitor_interval",
"../../../api/transport:network_control",
"../../../rtc_base:rtc_base_approved",
]
}
if (rtc_include_tests) {
rtc_source_set("pcc_unittests") {
testonly = true
sources = [
"monitor_interval_unittest.cc",
"rtt_tracker_unittest.cc",
"utility_function_unittest.cc",
]
deps = [
":monitor_interval",
":rtt_tracker",
":utility_function",
"../../../api/transport:network_control_test",
"../../../api/units:data_rate",
"../../../api/units:time_delta",

View file

@ -0,0 +1,84 @@
/*
* 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/pcc/utility_function.h"
#include <algorithm>
#include <cmath>
#include <vector>
namespace webrtc {
namespace pcc {
VivaceUtilityFunction::VivaceUtilityFunction(
double delay_gradient_coefficient,
double loss_coefficient,
double throughput_coefficient,
double throughput_power,
double delay_gradient_threshold,
double delay_gradient_negative_bound)
: delay_gradient_coefficient_(delay_gradient_coefficient),
loss_coefficient_(loss_coefficient),
throughput_power_(throughput_power),
throughput_coefficient_(throughput_coefficient),
delay_gradient_threshold_(delay_gradient_threshold),
delay_gradient_negative_bound_(delay_gradient_negative_bound) {
RTC_DCHECK_GE(delay_gradient_negative_bound_, 0);
}
double VivaceUtilityFunction::Compute(
const PccMonitorInterval& monitor_interval) const {
RTC_DCHECK(monitor_interval.IsFeedbackCollectionDone());
double bitrate = monitor_interval.GetTargetSendingRate().bps();
double loss_rate = monitor_interval.GetLossRate();
double rtt_gradient =
monitor_interval.ComputeDelayGradient(delay_gradient_threshold_);
rtt_gradient = std::max(rtt_gradient, -delay_gradient_negative_bound_);
return (throughput_coefficient_ * std::pow(bitrate, throughput_power_)) -
(delay_gradient_coefficient_ * bitrate * rtt_gradient) -
(loss_coefficient_ * bitrate * loss_rate);
}
VivaceUtilityFunction::~VivaceUtilityFunction() = default;
ModifiedVivaceUtilityFunction::ModifiedVivaceUtilityFunction(
double delay_gradient_coefficient,
double loss_coefficient,
double throughput_coefficient,
double throughput_power,
double delay_gradient_threshold,
double delay_gradient_negative_bound)
: delay_gradient_coefficient_(delay_gradient_coefficient),
loss_coefficient_(loss_coefficient),
throughput_power_(throughput_power),
throughput_coefficient_(throughput_coefficient),
delay_gradient_threshold_(delay_gradient_threshold),
delay_gradient_negative_bound_(delay_gradient_negative_bound) {
RTC_DCHECK_GE(delay_gradient_negative_bound_, 0);
}
double ModifiedVivaceUtilityFunction::Compute(
const PccMonitorInterval& monitor_interval) const {
RTC_DCHECK(monitor_interval.IsFeedbackCollectionDone());
double bitrate = monitor_interval.GetTargetSendingRate().bps();
double loss_rate = monitor_interval.GetLossRate();
double rtt_gradient =
monitor_interval.ComputeDelayGradient(delay_gradient_threshold_);
rtt_gradient = std::max(rtt_gradient, -delay_gradient_negative_bound_);
return (throughput_coefficient_ * std::pow(bitrate, throughput_power_) *
bitrate) -
(delay_gradient_coefficient_ * bitrate * bitrate * rtt_gradient) -
(loss_coefficient_ * bitrate * bitrate * loss_rate);
}
ModifiedVivaceUtilityFunction::~ModifiedVivaceUtilityFunction() = default;
} // namespace pcc
} // namespace webrtc

View file

@ -0,0 +1,79 @@
/*
* 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_PCC_UTILITY_FUNCTION_H_
#define MODULES_CONGESTION_CONTROLLER_PCC_UTILITY_FUNCTION_H_
#include "api/transport/network_control.h"
#include "modules/congestion_controller/pcc/monitor_interval.h"
namespace webrtc {
namespace pcc {
// Utility function is used by PCC to transform the performance statistics
// (sending rate, loss rate, packets latency) gathered at one monitor interval
// into a numerical value.
// https://www.usenix.org/conference/nsdi18/presentation/dong
class PccUtilityFunctionInterface {
public:
virtual double Compute(const PccMonitorInterval& monitor_interval) const = 0;
virtual ~PccUtilityFunctionInterface() = default;
};
// Vivace utility function were suggested in the paper "PCC Vivace:
// Online-Learning Congestion Control", Mo Dong et all.
class VivaceUtilityFunction : public PccUtilityFunctionInterface {
public:
VivaceUtilityFunction(double delay_gradient_coefficient,
double loss_coefficient,
double throughput_coefficient,
double throughput_power,
double delay_gradient_threshold,
double delay_gradient_negative_bound);
double Compute(const PccMonitorInterval& monitor_interval) const override;
~VivaceUtilityFunction() override;
private:
const double delay_gradient_coefficient_;
const double loss_coefficient_;
const double throughput_power_;
const double throughput_coefficient_;
const double delay_gradient_threshold_;
const double delay_gradient_negative_bound_;
};
// This utility function were obtained by tuning Vivace utility function.
// The main difference is that gradient of modified utilify funtion (as well as
// rate updates) scales proportionally to the sending rate which leads to
// better performance in case of single sender.
class ModifiedVivaceUtilityFunction : public PccUtilityFunctionInterface {
public:
ModifiedVivaceUtilityFunction(double delay_gradient_coefficient,
double loss_coefficient,
double throughput_coefficient,
double throughput_power,
double delay_gradient_threshold,
double delay_gradient_negative_bound);
double Compute(const PccMonitorInterval& monitor_interval) const override;
~ModifiedVivaceUtilityFunction() override;
private:
const double delay_gradient_coefficient_;
const double loss_coefficient_;
const double throughput_power_;
const double throughput_coefficient_;
const double delay_gradient_threshold_;
const double delay_gradient_negative_bound_;
};
} // namespace pcc
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_PCC_UTILITY_FUNCTION_H_

View file

@ -0,0 +1,102 @@
/*
* 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 <vector>
#include "modules/congestion_controller/pcc/utility_function.h"
#include "test/gtest.h"
namespace webrtc {
namespace pcc {
namespace test {
namespace {
constexpr double kLossCoefficient = 11.35;
constexpr double kThroughputPower = 0.9;
constexpr double kThroughputCoefficient = 1;
constexpr double kDelayGradientNegativeBound = 10;
const Timestamp kStartTime = Timestamp::us(0);
const TimeDelta kPacketsDelta = TimeDelta::ms(1);
const TimeDelta kIntervalDuration = TimeDelta::ms(100);
const DataRate kSendingBitrate = DataRate::bps(1000);
const DataSize kDefaultDataSize = DataSize::bytes(100);
const TimeDelta kDefaultDelay = TimeDelta::ms(100);
std::vector<PacketResult> CreatePacketResults(
const std::vector<Timestamp>& packets_send_times,
const std::vector<Timestamp>& packets_received_times = {},
const std::vector<DataSize>& packets_sizes = {}) {
std::vector<PacketResult> packet_results;
PacketResult packet_result;
SentPacket sent_packet;
for (size_t i = 0; i < packets_send_times.size(); ++i) {
sent_packet.send_time = packets_send_times[i];
if (packets_sizes.empty()) {
sent_packet.size = kDefaultDataSize;
} else {
sent_packet.size = packets_sizes[i];
}
packet_result.sent_packet = sent_packet;
if (packets_received_times.empty()) {
packet_result.receive_time = packets_send_times[i] + kDefaultDelay;
} else {
packet_result.receive_time = packets_received_times[i];
}
packet_results.push_back(packet_result);
}
return packet_results;
}
} // namespace
TEST(PccVivaceUtilityFunctionTest,
UtilityIsThroughputTermIfAllRestCoefficientsAreZero) {
VivaceUtilityFunction utility_function(0, 0, kThroughputCoefficient,
kThroughputPower, 0,
kDelayGradientNegativeBound);
PccMonitorInterval monitor_interval(kSendingBitrate, kStartTime,
kIntervalDuration);
monitor_interval.OnPacketsFeedback(CreatePacketResults(
{kStartTime + kPacketsDelta, kStartTime + 2 * kPacketsDelta,
kStartTime + 3 * kPacketsDelta, kStartTime + 2 * kIntervalDuration},
{kStartTime + kPacketsDelta + kDefaultDelay, Timestamp::Infinity(),
kStartTime + kDefaultDelay + 3 * kPacketsDelta, Timestamp::Infinity()},
{kDefaultDataSize, kDefaultDataSize, kDefaultDataSize,
kDefaultDataSize}));
EXPECT_DOUBLE_EQ(utility_function.Compute(monitor_interval),
kThroughputCoefficient *
std::pow(kSendingBitrate.bps(), kThroughputPower));
}
TEST(PccVivaceUtilityFunctionTest,
LossTermIsNonZeroIfLossCoefficientIsNonZero) {
VivaceUtilityFunction utility_function(
0, kLossCoefficient, kThroughputCoefficient, kThroughputPower, 0,
kDelayGradientNegativeBound);
PccMonitorInterval monitor_interval(kSendingBitrate, kStartTime,
kIntervalDuration);
monitor_interval.OnPacketsFeedback(CreatePacketResults(
{kStartTime + kPacketsDelta, kStartTime + 2 * kPacketsDelta,
kStartTime + 5 * kPacketsDelta, kStartTime + 2 * kIntervalDuration},
{kStartTime + kDefaultDelay, Timestamp::Infinity(),
kStartTime + kDefaultDelay, kStartTime + 3 * kIntervalDuration},
{}));
// The second packet was lost.
EXPECT_DOUBLE_EQ(utility_function.Compute(monitor_interval),
kThroughputCoefficient *
std::pow(kSendingBitrate.bps(), kThroughputPower) -
kLossCoefficient * kSendingBitrate.bps() *
monitor_interval.GetLossRate());
}
} // namespace test
} // namespace pcc
} // namespace webrtc