[SlackedPacer] Add experiment arm for high precision if long queue time.
This CL adds flag "max_queue_time", e.g:
WebRTC-SlackedTaskQueuePacedSender/Enabled:true,max_queue_time:75ms
If the PacingController's ExpectedQueueTime() is greater than or equal
to "max_queue_time" then we will use high precision delayed tasks to
ensure a smoother (less bursty) pacing of packets.
This should only get triggered in ultra high definition scenarios or
temporarily during key frames being sent. I have confirmed manually that
with the flag set to 75 ms I get low precision when not sending key
frames and temporarily get high precision for 5-15 delayed tasks during
the sending of a key frame.
Bug: webrtc:13957
Change-Id: I3c8aeba5fe18812ed0187610cd3f92a375bc6f18
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/258623
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36538}
diff --git a/modules/pacing/task_queue_paced_sender.cc b/modules/pacing/task_queue_paced_sender.cc
index 1ae182c..a597f07 100644
--- a/modules/pacing/task_queue_paced_sender.cc
+++ b/modules/pacing/task_queue_paced_sender.cc
@@ -15,6 +15,8 @@
#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
+#include "rtc_base/experiments/field_trial_parser.h"
+#include "rtc_base/experiments/field_trial_units.h"
#include "rtc_base/trace_event.h"
namespace webrtc {
@@ -28,6 +30,15 @@
const int TaskQueuePacedSender::kNoPacketHoldback = -1;
+TaskQueuePacedSender::SlackedPacerFlags::SlackedPacerFlags(
+ const FieldTrialsView& field_trials)
+ : allow_low_precision("Enabled"),
+ max_low_precision_expected_queue_time("max_queue_time") {
+ ParseFieldTrial(
+ {&allow_low_precision, &max_low_precision_expected_queue_time},
+ field_trials.Lookup(kSlackedTaskQueuePacedSenderFieldTrial));
+}
+
TaskQueuePacedSender::TaskQueuePacedSender(
Clock* clock,
PacingController::PacketSender* packet_sender,
@@ -36,13 +47,13 @@
TimeDelta max_hold_back_window,
int max_hold_back_window_in_packets)
: clock_(clock),
- allow_low_precision_(
- field_trials.IsEnabled(kSlackedTaskQueuePacedSenderFieldTrial)),
- max_hold_back_window_(allow_low_precision_
+ slacked_pacer_flags_(field_trials),
+ max_hold_back_window_(slacked_pacer_flags_.allow_low_precision
? PacingController::kMinSleepTime
: max_hold_back_window),
- max_hold_back_window_in_packets_(
- allow_low_precision_ ? 0 : max_hold_back_window_in_packets),
+ max_hold_back_window_in_packets_(slacked_pacer_flags_.allow_low_precision
+ ? 0
+ : max_hold_back_window_in_packets),
pacing_controller_(clock,
packet_sender,
field_trials,
@@ -279,9 +290,19 @@
next_process_time_ > next_send_time) {
// Prefer low precision if allowed and not probing.
TaskQueueBase::DelayPrecision precision =
- allow_low_precision_ && !pacing_controller_.IsProbing()
+ slacked_pacer_flags_.allow_low_precision &&
+ !pacing_controller_.IsProbing()
? TaskQueueBase::DelayPrecision::kLow
: TaskQueueBase::DelayPrecision::kHigh;
+ // Optionally disable low precision if the expected queue time is greater
+ // than `max_low_precision_expected_queue_time`.
+ if (precision == TaskQueueBase::DelayPrecision::kLow &&
+ slacked_pacer_flags_.max_low_precision_expected_queue_time &&
+ pacing_controller_.ExpectedQueueTime() >=
+ slacked_pacer_flags_.max_low_precision_expected_queue_time
+ .Value()) {
+ precision = TaskQueueBase::DelayPrecision::kHigh;
+ }
task_queue_.PostDelayedTaskWithPrecision(
precision,
diff --git a/modules/pacing/task_queue_paced_sender.h b/modules/pacing/task_queue_paced_sender.h
index d72982f..32c5c1f 100644
--- a/modules/pacing/task_queue_paced_sender.h
+++ b/modules/pacing/task_queue_paced_sender.h
@@ -28,6 +28,7 @@
#include "modules/pacing/pacing_controller.h"
#include "modules/pacing/rtp_packet_pacer.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/numerics/exp_filter.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/thread_annotations.h"
@@ -129,16 +130,24 @@
Stats GetStats() const;
Clock* const clock_;
- // If `kSlackedTaskQueuePacedSenderFieldTrial` is enabled, delayed tasks
- // invoking MaybeProcessPackets() are scheduled using low precision instead of
- // high precision, resulting in less idle wake ups and packets being sent in
- // bursts if the `task_queue_` implementation supports slack.
- //
- // When probing, high precision is used regardless of `allow_low_precision_`
- // to ensure good bandwidth estimation.
- const bool allow_low_precision_;
+ struct SlackedPacerFlags {
+ // Parses `kSlackedTaskQueuePacedSenderFieldTrial`. Example:
+ // --force-fieldtrials=WebRTC-SlackedTaskQueuePacedSender/Enabled,max_queue_time:75ms/
+ explicit SlackedPacerFlags(const FieldTrialsView& field_trials);
+ // When "Enabled", delayed tasks invoking MaybeProcessPackets() are
+ // scheduled using low precision instead of high precision, resulting in
+ // less idle wake ups and packets being sent in bursts if the `task_queue_`
+ // implementation supports slack. When probing, high precision is used
+ // regardless to ensure good bandwidth estimation.
+ FieldTrialFlag allow_low_precision;
+ // Controlled via the "max_queue_time" experiment arm. If set, uses high
+ // precision scheduling of MaybeProcessPackets() whenever the expected queue
+ // time is greater than or equal to this value.
+ FieldTrialOptional<TimeDelta> max_low_precision_expected_queue_time;
+ };
+ const SlackedPacerFlags slacked_pacer_flags_;
// The holdback window prevents too frequent delayed MaybeProcessPackets()
- // calls. These are only applicable if `allow_low_precision_` is false.
+ // calls. These are only applicable if `allow_low_precision` is false.
const TimeDelta max_hold_back_window_;
const int max_hold_back_window_in_packets_;