Stop Posting tasks when we don't need to.
Under the combined network/worker thread project, tasks
are unnecessarily posted to the same thread.
This CL reaps 90% overhead savings in sent packet feedback
as measured with Perfetto under a 49p Meet call.
The identity of the posted calls was uncovered with WebRTC/Chrome's
new location-aware tracing.
TESTED=presubmit + local Meet calls.
Bug: chromium:1373439
Change-Id: I0c43aa4de884831838747d52b21c45fd360106e8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/295780
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Commit-Queue: Markus Handell <handellm@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39484}
diff --git a/api/transport/network_types.h b/api/transport/network_types.h
index 29a7cf7..a62c350 100644
--- a/api/transport/network_types.h
+++ b/api/transport/network_types.h
@@ -233,6 +233,12 @@
NetworkControlUpdate();
NetworkControlUpdate(const NetworkControlUpdate&);
~NetworkControlUpdate();
+
+ bool has_updates() const {
+ return congestion_window.has_value() || pacer_config.has_value() ||
+ !probe_cluster_configs.empty() || target_rate.has_value();
+ }
+
absl::optional<DataSize> congestion_window;
absl::optional<PacerConfig> pacer_config;
std::vector<ProbeClusterConfig> probe_cluster_configs;
diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc
index 0b467b7..2d871ce 100644
--- a/call/rtp_transport_controller_send.cc
+++ b/call/rtp_transport_controller_send.cc
@@ -181,12 +181,19 @@
}
void RtpTransportControllerSend::UpdateCongestedState() {
+ if (auto update = GetCongestedStateUpdate()) {
+ is_congested_ = update.value();
+ pacer_.SetCongested(update.value());
+ }
+}
+
+absl::optional<bool> RtpTransportControllerSend::GetCongestedStateUpdate()
+ const {
bool congested = transport_feedback_adapter_.GetOutstandingData() >=
congestion_window_size_;
- if (congested != is_congested_) {
- is_congested_ = congested;
- pacer_.SetCongested(congested);
- }
+ if (congested != is_congested_)
+ return congested;
+ return absl::nullopt;
}
MaybeWorkerThread* RtpTransportControllerSend::GetWorkerQueue() {
@@ -392,27 +399,73 @@
void RtpTransportControllerSend::OnSentPacket(
const rtc::SentPacket& sent_packet) {
// Normally called on the network thread !
+ // TODO(bugs.webrtc.org/137439): Clarify other thread contexts calling in, and
+ // simplify task posting logic when the combined network/worker project
+ // launches.
+ if (TaskQueueBase::Current() != task_queue_.TaskQueueForPost()) {
+ // We can't use SafeTask here if we are using an owned task queue, because
+ // the safety flag will be destroyed when RtpTransportControllerSend is
+ // destroyed on the worker thread. But we must use SafeTask if we are using
+ // the worker thread, since the worker thread outlives
+ // RtpTransportControllerSend.
+ task_queue_.TaskQueueForPost()->PostTask(
+ task_queue_.MaybeSafeTask(safety_.flag(), [this, sent_packet]() {
+ RTC_DCHECK_RUN_ON(&task_queue_);
+ ProcessSentPacket(sent_packet, /*posted_to_worker=*/true);
+ }));
+ return;
+ }
- // We can not use SafeTask here if we are using an owned task queue, because
- // the safety flag will be destroyed when RtpTransportControllerSend is
- // destroyed on the worker thread. But we must use SafeTask if we are using
- // the worker thread, since the worker thread outlive
- // RtpTransportControllerSend.
- task_queue_.TaskQueueForPost()->PostTask(
- task_queue_.MaybeSafeTask(safety_.flag(), [this, sent_packet]() {
- RTC_DCHECK_RUN_ON(&task_queue_);
- absl::optional<SentPacket> packet_msg =
- transport_feedback_adapter_.ProcessSentPacket(sent_packet);
- if (packet_msg) {
- // Only update outstanding data if:
- // 1. Packet feedback is used.
- // 2. The packet has not yet received an acknowledgement.
- // 3. It is not a retransmission of an earlier packet.
- UpdateCongestedState();
- if (controller_)
- PostUpdates(controller_->OnSentPacket(*packet_msg));
- }
- }));
+ RTC_DCHECK_RUN_ON(&task_queue_);
+ ProcessSentPacket(sent_packet, /*posted_to_worker=*/false);
+}
+
+// RTC_RUN_ON(task_queue_)
+void RtpTransportControllerSend::ProcessSentPacket(
+ const rtc::SentPacket& sent_packet,
+ bool posted_to_worker) {
+ absl::optional<SentPacket> packet_msg =
+ transport_feedback_adapter_.ProcessSentPacket(sent_packet);
+ if (!packet_msg)
+ return;
+
+ auto congestion_update = GetCongestedStateUpdate();
+ NetworkControlUpdate control_update;
+ if (controller_)
+ control_update = controller_->OnSentPacket(*packet_msg);
+ if (!congestion_update && !control_update.has_updates())
+ return;
+ if (posted_to_worker) {
+ ProcessSentPacketUpdates(std::move(control_update));
+ } else {
+ // TODO(bugs.webrtc.org/137439): Aim to remove downstream locks to permit
+ // removing this PostTask.
+ // At least in test situations (and possibly in production environments), we
+ // may get here synchronously with locks taken in PacketRouter::SendPacket.
+ // Because the pacer may at times synchronously re-enter
+ // PacketRouter::SendPacket, we need to break the chain here and PostTask to
+ // get out of the lock. In testing, having updates to process happens pretty
+ // rarely so we do not usually get here.
+ task_queue_.TaskQueueForPost()->PostTask(task_queue_.MaybeSafeTask(
+ safety_.flag(),
+ [this, control_update = std::move(control_update)]() mutable {
+ RTC_DCHECK_RUN_ON(&task_queue_);
+ ProcessSentPacketUpdates(std::move(control_update));
+ }));
+ }
+}
+
+// RTC_RUN_ON(task_queue_)
+void RtpTransportControllerSend::ProcessSentPacketUpdates(
+ NetworkControlUpdate updates) {
+ // Only update outstanding data if:
+ // 1. Packet feedback is used.
+ // 2. The packet has not yet received an acknowledgement.
+ // 3. It is not a retransmission of an earlier packet.
+ UpdateCongestedState();
+ if (controller_) {
+ PostUpdates(std::move(updates));
+ }
}
void RtpTransportControllerSend::OnReceivedPacket(
diff --git a/call/rtp_transport_controller_send.h b/call/rtp_transport_controller_send.h
index 9b41a0a..eaac55f 100644
--- a/call/rtp_transport_controller_send.h
+++ b/call/rtp_transport_controller_send.h
@@ -141,6 +141,11 @@
void PostUpdates(NetworkControlUpdate update) RTC_RUN_ON(task_queue_);
void UpdateControlState() RTC_RUN_ON(task_queue_);
void UpdateCongestedState() RTC_RUN_ON(task_queue_);
+ absl::optional<bool> GetCongestedStateUpdate() const RTC_RUN_ON(task_queue_);
+ void ProcessSentPacket(const rtc::SentPacket& sent_packet,
+ bool posted_to_worker) RTC_RUN_ON(task_queue_);
+ void ProcessSentPacketUpdates(NetworkControlUpdate updates)
+ RTC_RUN_ON(task_queue_);
Clock* const clock_;
RtcEventLog* const event_log_;