From 0c563a42ec1f207e442763afa0dbd09d5511b0b2 Mon Sep 17 00:00:00 2001 From: Victor Boivie Date: Tue, 27 Apr 2021 10:24:01 +0200 Subject: [PATCH] Use unordered_map in RTCPReceiver In highly loaded media servers, RTCPReceiver's use of std::map attributes to ~0.5% CPU. It's mostly ::find and the [] operator, and they are all keyed by SSRC, which is an unordered data type. This makes these maps suitable as unordered maps, as they have constant time complexity for lookups. Bug: webrtc:12689 Change-Id: I7b305e233fcbed0e452632946ab0de5ee66f8dda Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/216321 Commit-Queue: Victor Boivie Reviewed-by: Danil Chapovalov Reviewed-by: Mirko Bonadei Cr-Commit-Position: refs/heads/master@{#33850} --- modules/rtp_rtcp/source/rtcp_receiver.h | 12 +++++++++--- modules/rtp_rtcp/source/rtcp_receiver_unittest.cc | 14 ++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h index a9f602f845..918d349392 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.h +++ b/modules/rtp_rtcp/source/rtcp_receiver.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "api/array_view.h" @@ -145,6 +146,11 @@ class RTCPReceiver final { struct TmmbrInformation; struct RrtrInformation; struct LastFirStatus; + + // TODO(boivie): `ReportBlockDataMap` and `ReportBlockMap` should be converted + // to std::unordered_map, but as there are too many tests that assume a + // specific order, it's not easily done. + // RTCP report blocks mapped by remote SSRC. using ReportBlockDataMap = std::map; // RTCP report blocks map mapped by source SSRC. @@ -273,7 +279,7 @@ class RTCPReceiver final { std::list received_rrtrs_ RTC_GUARDED_BY(rtcp_receiver_lock_); // Received RRTR information mapped by remote ssrc. - std::map::iterator> + std::unordered_map::iterator> received_rrtrs_ssrc_it_ RTC_GUARDED_BY(rtcp_receiver_lock_); // Estimated rtt, zero when there is no valid estimate. @@ -282,11 +288,11 @@ class RTCPReceiver final { int64_t oldest_tmmbr_info_ms_ RTC_GUARDED_BY(rtcp_receiver_lock_); // Mapped by remote ssrc. - std::map tmmbr_infos_ + std::unordered_map tmmbr_infos_ RTC_GUARDED_BY(rtcp_receiver_lock_); ReportBlockMap received_report_blocks_ RTC_GUARDED_BY(rtcp_receiver_lock_); - std::map last_fir_ + std::unordered_map last_fir_ RTC_GUARDED_BY(rtcp_receiver_lock_); // The last time we received an RTCP Report block for this module. diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index 5739c51f65..068a110771 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -51,6 +51,7 @@ using rtcp::ReceiveTimeInfo; using ::testing::_; using ::testing::AllOf; using ::testing::ElementsAreArray; +using ::testing::Eq; using ::testing::Field; using ::testing::InSequence; using ::testing::IsEmpty; @@ -1266,16 +1267,17 @@ TEST(RtcpReceiverTest, TmmbrThreeConstraintsTimeOut) { mocks.clock.AdvanceTimeMilliseconds(5000); } // It is now starttime + 15. - std::vector candidate_set = receiver.TmmbrReceived(); - ASSERT_EQ(3u, candidate_set.size()); - EXPECT_EQ(30000U, candidate_set[0].bitrate_bps()); + EXPECT_THAT(receiver.TmmbrReceived(), + AllOf(SizeIs(3), + Each(Property(&rtcp::TmmbItem::bitrate_bps, Eq(30'000U))))); // We expect the timeout to be 25 seconds. Advance the clock by 12 // seconds, timing out the first packet. mocks.clock.AdvanceTimeMilliseconds(12000); - candidate_set = receiver.TmmbrReceived(); - ASSERT_EQ(2u, candidate_set.size()); - EXPECT_EQ(kSenderSsrc + 1, candidate_set[0].ssrc()); + EXPECT_THAT(receiver.TmmbrReceived(), + UnorderedElementsAre( + Property(&rtcp::TmmbItem::ssrc, Eq(kSenderSsrc + 1)), + Property(&rtcp::TmmbItem::ssrc, Eq(kSenderSsrc + 2)))); } TEST(RtcpReceiverTest, Callbacks) {