From 3168781d2fb06af02cfaad453e74fac7832c3cf9 Mon Sep 17 00:00:00 2001 From: isheriff Date: Tue, 4 Oct 2016 08:43:09 -0700 Subject: [PATCH] Add AlrDetector This is a simple application limited region detector that is quite conservative at the moment. We detect as being application-limited if we see sending rate as less than 30% of the estimated bandwidth over 500 ms. The moment we detect a single burst above 30% over a 100 ms period, we consider ourselves network limited. This class is currently not used. A follow up CL will leverage this to enable probing. BUG=webrtc:6332 Review-Url: https://codereview.webrtc.org/2340763004 Cr-Commit-Position: refs/heads/master@{#14505} --- webrtc/modules/BUILD.gn | 1 + webrtc/modules/pacing/BUILD.gn | 2 + webrtc/modules/pacing/alr_detector.cc | 80 +++++++++++++++++++ webrtc/modules/pacing/alr_detector.h | 48 +++++++++++ .../modules/pacing/alr_detector_unittest.cc | 48 +++++++++++ webrtc/modules/pacing/paced_sender.cc | 23 ++++-- webrtc/modules/pacing/paced_sender.h | 6 +- webrtc/modules/pacing/pacing.gypi | 2 + 8 files changed, 201 insertions(+), 9 deletions(-) create mode 100644 webrtc/modules/pacing/alr_detector.cc create mode 100644 webrtc/modules/pacing/alr_detector.h create mode 100644 webrtc/modules/pacing/alr_detector_unittest.cc diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index daeb7e9d43..8e181d3675 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -382,6 +382,7 @@ if (rtc_include_tests) { "congestion_controller/transport_feedback_adapter_unittest.cc", "media_file/media_file_unittest.cc", "module_common_types_unittest.cc", + "pacing/alr_detector_unittest.cc", "pacing/bitrate_prober_unittest.cc", "pacing/paced_sender_unittest.cc", "pacing/packet_router_unittest.cc", diff --git a/webrtc/modules/pacing/BUILD.gn b/webrtc/modules/pacing/BUILD.gn index 7a16297329..03c33d5ea7 100644 --- a/webrtc/modules/pacing/BUILD.gn +++ b/webrtc/modules/pacing/BUILD.gn @@ -10,6 +10,8 @@ import("../../build/webrtc.gni") rtc_static_library("pacing") { sources = [ + "alr_detector.cc", + "alr_detector.h", "bitrate_prober.cc", "bitrate_prober.h", "paced_sender.cc", diff --git a/webrtc/modules/pacing/alr_detector.cc b/webrtc/modules/pacing/alr_detector.cc new file mode 100644 index 0000000000..677c7e018e --- /dev/null +++ b/webrtc/modules/pacing/alr_detector.cc @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016 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/pacing/alr_detector.h" + +#include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" + +namespace { + +// Time period over which outgoing traffic is measured and considered a single +// data point. +constexpr int kMeasurementPeriodMs = 100; + +// Minimum number of consecutive measurements over |kMeasurementPeriodMs| time +// that indicate sending rate is below |kUsagePercent| to consider being +// application limited. +constexpr int kApplicationLimitedThreshold = 5; + +// Sent traffic percentage as a function of network capaicty to consider traffic +// as application limited. +// NOTE: This is intentionally conservative at the moment until BW adjustments +// of application limited region is fine tuned. +constexpr int kUsagePercent = 30; + +} // namespace + +namespace webrtc { + +AlrDetector::AlrDetector() + : measurement_interval_bytes_sent_(0), + measurement_interval_elapsed_time_ms_(0), + estimated_bitrate_bps_(0), + application_limited_count_(0) {} + +AlrDetector::~AlrDetector() {} + +void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t elapsed_time_ms) { + if (measurement_interval_elapsed_time_ms_ > kMeasurementPeriodMs) { + RTC_DCHECK(estimated_bitrate_bps_); + int max_bytes = + (measurement_interval_elapsed_time_ms_ * estimated_bitrate_bps_) / + (8 * 1000); + RTC_DCHECK_GT(max_bytes, 0); + int utilization = + static_cast((measurement_interval_bytes_sent_ * 100) / max_bytes); + if (utilization < kUsagePercent) { + application_limited_count_++; + if (application_limited_count_ == kApplicationLimitedThreshold) + LOG(LS_INFO) << "ALR start"; + } else { + if (application_limited_count_ >= kApplicationLimitedThreshold) + LOG(LS_INFO) << "ALR stop"; + application_limited_count_ = 0; + } + measurement_interval_elapsed_time_ms_ = elapsed_time_ms; + measurement_interval_bytes_sent_ = bytes_sent; + } else { + measurement_interval_elapsed_time_ms_ += elapsed_time_ms; + measurement_interval_bytes_sent_ += bytes_sent; + } +} + +void AlrDetector::SetEstimatedBitrate(int bitrate_bps) { + RTC_DCHECK(bitrate_bps); + estimated_bitrate_bps_ = bitrate_bps; +} + +bool AlrDetector::InApplicationLimitedRegion() { + return application_limited_count_ >= kApplicationLimitedThreshold; +} + +} // namespace webrtc diff --git a/webrtc/modules/pacing/alr_detector.h b/webrtc/modules/pacing/alr_detector.h new file mode 100644 index 0000000000..6250cc9053 --- /dev/null +++ b/webrtc/modules/pacing/alr_detector.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 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 WEBRTC_MODULES_PACING_ALR_DETECTOR_H_ +#define WEBRTC_MODULES_PACING_ALR_DETECTOR_H_ + +#include "webrtc/common_types.h" +#include "webrtc/modules/pacing/paced_sender.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +// Application limited region detector is a class that utilizes signals of +// elapsed time and bytes sent to estimate whether network traffic is +// currently limited by the application's ability to generate traffic. +// +// AlrDetector provides a signal that can be utilized to adjust +// estimate bandwidth. +// Note: This class is not thread-safe. +class AlrDetector { + public: + AlrDetector(); + ~AlrDetector(); + void OnBytesSent(size_t bytes_sent, int64_t elapsed_time_ms); + // Set current estimated bandwidth. + void SetEstimatedBitrate(int bitrate_bps); + // Returns true if currently in application-limited region. + bool InApplicationLimitedRegion(); + + private: + size_t measurement_interval_bytes_sent_; + int64_t measurement_interval_elapsed_time_ms_; + int estimated_bitrate_bps_; + // Number of consecutive periods over which we observe traffic is application + // limited. + int application_limited_count_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_PACING_ALR_DETECTOR_H_ diff --git a/webrtc/modules/pacing/alr_detector_unittest.cc b/webrtc/modules/pacing/alr_detector_unittest.cc new file mode 100644 index 0000000000..a30f9fa863 --- /dev/null +++ b/webrtc/modules/pacing/alr_detector_unittest.cc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 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/test/gtest.h" +#include "webrtc/modules/pacing/alr_detector.h" + +namespace { + +constexpr int kMeasuredIntervalMs = 110; +constexpr int kEstimatedBitrateBps = 300000; +constexpr int kBytesInIntervalAtEstimatedBitrate = + (kEstimatedBitrateBps / 8) * kMeasuredIntervalMs / 1000; + +} // namespace + +namespace webrtc { + +TEST(AlrDetectorTest, ApplicationLimitedWhenLittleDataSent) { + AlrDetector alr_detector; + + alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); + for (int i = 0; i < 6; i++) + alr_detector.OnBytesSent(0, kMeasuredIntervalMs); + EXPECT_EQ(alr_detector.InApplicationLimitedRegion(), true); + + for (int i = 0; i < 6; i++) + alr_detector.OnBytesSent(100, kMeasuredIntervalMs); + EXPECT_EQ(alr_detector.InApplicationLimitedRegion(), true); +} + +TEST(AlrDetectorTest, NetworkLimitedWhenSendingCloseToEstimate) { + AlrDetector alr_detector; + + alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); + for (int i = 0; i < 6; i++) + alr_detector.OnBytesSent(kBytesInIntervalAtEstimatedBitrate, + kMeasuredIntervalMs); + EXPECT_EQ(alr_detector.InApplicationLimitedRegion(), false); +} + +} // namespace webrtc diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc index fe918bbbb3..6c5e183a78 100644 --- a/webrtc/modules/pacing/paced_sender.cc +++ b/webrtc/modules/pacing/paced_sender.cc @@ -19,6 +19,7 @@ #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/modules/include/module_common_types.h" +#include "webrtc/modules/pacing/alr_detector.h" #include "webrtc/modules/pacing/bitrate_prober.h" #include "webrtc/system_wrappers/include/clock.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" @@ -248,6 +249,7 @@ const float PacedSender::kDefaultPaceMultiplier = 2.5f; PacedSender::PacedSender(Clock* clock, PacketSender* packet_sender) : clock_(clock), packet_sender_(packet_sender), + alr_detector_(new AlrDetector()), critsect_(CriticalSectionWrapper::CreateCriticalSection()), paused_(false), media_budget_(new paced_sender::IntervalBudget(0)), @@ -260,7 +262,7 @@ PacedSender::PacedSender(Clock* clock, PacketSender* packet_sender) time_last_update_us_(clock->TimeInMicroseconds()), packets_(new paced_sender::PacketQueue(clock)), packet_counter_(0) { - UpdateBytesPerInterval(kMinPacketLimitMs); + UpdateBudgetWithElapsedTime(kMinPacketLimitMs); } PacedSender::~PacedSender() {} @@ -298,6 +300,7 @@ void PacedSender::SetEstimatedBitrate(uint32_t bitrate_bps) { pacing_bitrate_kbps_ = std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) * kDefaultPaceMultiplier; + alr_detector_->SetEstimatedBitrate(bitrate_bps); } void PacedSender::SetSendBitrateLimits(int min_send_bitrate_bps, @@ -397,8 +400,8 @@ void PacedSender::Process() { media_budget_->set_target_rate_kbps(target_bitrate_kbps); - int64_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms); - UpdateBytesPerInterval(delta_time_ms); + elapsed_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms); + UpdateBudgetWithElapsedTime(elapsed_time_ms); } bool is_probing = prober_->IsProbing(); @@ -443,6 +446,7 @@ void PacedSender::Process() { } if (is_probing && bytes_sent > 0) prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent); + alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms); } bool PacedSender::SendPacket(const paced_sender::Packet& packet, @@ -469,8 +473,7 @@ bool PacedSender::SendPacket(const paced_sender::Packet& packet, // are allocating bandwidth for audio. if (packet.priority != kHighPriority) { // Update media bytes sent. - media_budget_->UseBudget(packet.bytes); - padding_budget_->UseBudget(packet.bytes); + UpdateBudgetWithBytesSent(packet.bytes); } } @@ -484,14 +487,18 @@ size_t PacedSender::SendPadding(size_t padding_needed, int probe_cluster_id) { critsect_->Enter(); if (bytes_sent > 0) { - media_budget_->UseBudget(bytes_sent); - padding_budget_->UseBudget(bytes_sent); + UpdateBudgetWithBytesSent(bytes_sent); } return bytes_sent; } -void PacedSender::UpdateBytesPerInterval(int64_t delta_time_ms) { +void PacedSender::UpdateBudgetWithElapsedTime(int64_t delta_time_ms) { media_budget_->IncreaseBudget(delta_time_ms); padding_budget_->IncreaseBudget(delta_time_ms); } + +void PacedSender::UpdateBudgetWithBytesSent(size_t bytes_sent) { + media_budget_->UseBudget(bytes_sent); + padding_budget_->UseBudget(bytes_sent); +} } // namespace webrtc diff --git a/webrtc/modules/pacing/paced_sender.h b/webrtc/modules/pacing/paced_sender.h index 02d1dbd3d6..b11ae17fcd 100644 --- a/webrtc/modules/pacing/paced_sender.h +++ b/webrtc/modules/pacing/paced_sender.h @@ -21,6 +21,7 @@ #include "webrtc/typedefs.h" namespace webrtc { +class AlrDetector; class BitrateProber; class Clock; class CriticalSectionWrapper; @@ -132,7 +133,9 @@ class PacedSender : public Module, public RtpPacketSender { private: // Updates the number of bytes that can be sent for the next time interval. - void UpdateBytesPerInterval(int64_t delta_time_in_ms) + void UpdateBudgetWithElapsedTime(int64_t delta_time_in_ms) + EXCLUSIVE_LOCKS_REQUIRED(critsect_); + void UpdateBudgetWithBytesSent(size_t bytes) EXCLUSIVE_LOCKS_REQUIRED(critsect_); bool SendPacket(const paced_sender::Packet& packet, int probe_cluster_id) @@ -142,6 +145,7 @@ class PacedSender : public Module, public RtpPacketSender { Clock* const clock_; PacketSender* const packet_sender_; + std::unique_ptr alr_detector_ GUARDED_BY(critsect_); std::unique_ptr critsect_; bool paused_ GUARDED_BY(critsect_); diff --git a/webrtc/modules/pacing/pacing.gypi b/webrtc/modules/pacing/pacing.gypi index 90f663c1b0..2943f2d9a3 100644 --- a/webrtc/modules/pacing/pacing.gypi +++ b/webrtc/modules/pacing/pacing.gypi @@ -17,6 +17,8 @@ '<(webrtc_root)/modules/modules.gyp:rtp_rtcp', ], 'sources': [ + 'alr_detector.cc', + 'alr_detector.h', 'bitrate_prober.cc', 'bitrate_prober.h', 'paced_sender.cc',