Add parameter to control the pacer's burst outside of field trials.

BurstyPacer is currently controlled via field trials. In order for
Chrome to be able to have burst without relying on a field trial, this
parameter is added.

When all burst experiments have concluded we may be able to have a
hardcoded constant instead, but for now the parameter is added to
RTCConfiguration.

NOTRY=True

Bug: chromium:1354491
Change-Id: I386c1651dbbcbf309c15ea3d3380cf8f632b5429
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/283420
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38621}
This commit is contained in:
Henrik Boström
2022-11-15 09:23:19 +01:00
committed by WebRTC LUCI CQ
parent b21c979691
commit cf2856b01c
14 changed files with 103 additions and 19 deletions

View File

@ -57,7 +57,8 @@ TaskQueuePacedSender::TaskQueuePacedSender(
const FieldTrialsView& field_trials,
TaskQueueFactory* task_queue_factory,
TimeDelta max_hold_back_window,
int max_hold_back_window_in_packets)
int max_hold_back_window_in_packets,
absl::optional<TimeDelta> burst_interval)
: clock_(clock),
bursty_pacer_flags_(field_trials),
slacked_pacer_flags_(field_trials),
@ -85,6 +86,12 @@ TaskQueuePacedSender::TaskQueuePacedSender(
burst = slacked_burst;
}
}
// Burst can also be controlled via the `burst_interval` argument.
if (burst_interval.has_value() &&
(!burst.has_value() || burst.value() < burst_interval.value())) {
burst = burst_interval;
}
if (burst.has_value()) {
pacing_controller_.SetSendBurstInterval(burst.value());
}

View File

@ -39,16 +39,25 @@ class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender {
public:
static const int kNoPacketHoldback;
// The pacer can be configured using `field_trials` or specified parameters.
//
// The `hold_back_window` parameter sets a lower bound on time to sleep if
// there is currently a pacer queue and packets can't immediately be
// processed. Increasing this reduces thread wakeups at the expense of higher
// latency.
TaskQueuePacedSender(Clock* clock,
PacingController::PacketSender* packet_sender,
const FieldTrialsView& field_trials,
TaskQueueFactory* task_queue_factory,
TimeDelta max_hold_back_window,
int max_hold_back_window_in_packets);
//
// If the `burst_interval` parameter is set, the pacer is allowed to build up
// a packet "debt" that correspond to approximately the send rate during the
// specified interval. This greatly reduced wake ups by not pacing packets
// within the allowed burst budget.
TaskQueuePacedSender(
Clock* clock,
PacingController::PacketSender* packet_sender,
const FieldTrialsView& field_trials,
TaskQueueFactory* task_queue_factory,
TimeDelta max_hold_back_window,
int max_hold_back_window_in_packets,
absl::optional<TimeDelta> burst_interval = absl::nullopt);
~TaskQueuePacedSender() override;

View File

@ -253,6 +253,53 @@ TEST_P(TaskQueuePacedSenderTest, PacesPackets) {
EXPECT_NEAR((end_time - start_time).ms<double>(), 1000.0, 50.0);
}
// Same test as above, but with 0.5s of burst applied.
TEST_P(TaskQueuePacedSenderTest, PacesPacketsWithBurst) {
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
MockPacketRouter packet_router;
ScopedKeyValueConfig trials(GetParam());
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
time_controller.GetTaskQueueFactory(),
PacingController::kMinSleepTime,
TaskQueuePacedSender::kNoPacketHoldback,
// Half a second of bursting.
TimeDelta::Seconds(0.5));
// Insert a number of packets, covering one second.
static constexpr size_t kPacketsToSend = 42;
SequenceChecker sequence_checker;
pacer.SetPacingRates(
DataRate::BitsPerSec(kDefaultPacketSize * 8 * kPacketsToSend),
DataRate::Zero());
pacer.EnsureStarted();
pacer.EnqueuePackets(
GeneratePackets(RtpPacketMediaType::kVideo, kPacketsToSend));
// Expect all of them to be sent.
size_t packets_sent = 0;
Timestamp end_time = Timestamp::PlusInfinity();
EXPECT_CALL(packet_router, SendPacket)
.WillRepeatedly([&](std::unique_ptr<RtpPacketToSend> packet,
const PacedPacketInfo& cluster_info) {
++packets_sent;
if (packets_sent == kPacketsToSend) {
end_time = time_controller.GetClock()->CurrentTime();
}
EXPECT_EQ(sequence_checker.IsCurrent(), UsingWorkerThread(GetParam()));
});
const Timestamp start_time = time_controller.GetClock()->CurrentTime();
// Packets should be sent over a period of close to 1s. Expect a little
// lower than this since initial probing is a bit quicker.
time_controller.AdvanceTime(TimeDelta::Seconds(1));
EXPECT_EQ(packets_sent, kPacketsToSend);
ASSERT_TRUE(end_time.IsFinite());
// Because of half a second of burst, what would normally have been paced over
// ~1 second now takes ~0.5 seconds.
EXPECT_NEAR((end_time - start_time).ms<double>(), 500.0, 50.0);
}
TEST_P(TaskQueuePacedSenderTest, ReschedulesProcessOnRateChange) {
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
MockPacketRouter packet_router;