From 6d183ac27a6755497e35f197b8aaf41d6319aeaf Mon Sep 17 00:00:00 2001 From: hbos Date: Mon, 29 Aug 2016 07:20:33 -0700 Subject: [PATCH] RTCStatsReport: Take ownership of other's stats with TakeMembersFrom This would make it possible to gather stats on multiple threads, store the results in multiple reports and to merge the results. Added rtcstatsreport_unittest.cc, moving a RTCStatsReport-related test from rtcstats_unittest.cc. Added more unittests covering the order of stats and TakeMembersFrom. Also changed RTCStatsReport[] to RTCStatsReport::Get to avoid confusion with other usages of the [] operator. BUG=chromium:627816 NOTRY=True Review-Url: https://codereview.webrtc.org/2278433003 Cr-Commit-Position: refs/heads/master@{#13957} --- webrtc/api/rtcstatsreport.h | 6 +- webrtc/stats/BUILD.gn | 1 + webrtc/stats/rtcstats_unittest.cc | 35 ------- webrtc/stats/rtcstatsreport.cc | 11 +- webrtc/stats/rtcstatsreport_unittest.cc | 131 ++++++++++++++++++++++++ webrtc/stats/stats.gyp | 1 + 6 files changed, 148 insertions(+), 37 deletions(-) create mode 100644 webrtc/stats/rtcstatsreport_unittest.cc diff --git a/webrtc/api/rtcstatsreport.h b/webrtc/api/rtcstatsreport.h index 42237eba72..fbd78b93f4 100644 --- a/webrtc/api/rtcstatsreport.h +++ b/webrtc/api/rtcstatsreport.h @@ -55,9 +55,13 @@ class RTCStatsReport : public rtc::RefCountInterface { RTCStatsReport(const RTCStatsReport& other) = delete; bool AddStats(std::unique_ptr stats); - const RTCStats* operator[](const std::string& id) const; + const RTCStats* Get(const std::string& id) const; size_t size() const { return stats_.size(); } + // Takes ownership of all the stats in |victim|, leaving it empty. + void TakeMembersFrom(rtc::scoped_refptr victim); + + // Stats iterators. Stats are ordered lexicographically on |RTCStats::id|. ConstIterator begin() const; ConstIterator end() const; diff --git a/webrtc/stats/BUILD.gn b/webrtc/stats/BUILD.gn index 50f43515d4..2f69216772 100644 --- a/webrtc/stats/BUILD.gn +++ b/webrtc/stats/BUILD.gn @@ -37,6 +37,7 @@ if (rtc_include_tests) { testonly = true sources = [ "rtcstats_unittest.cc", + "rtcstatsreport_unittest.cc", ] configs += [ "..:common_config" ] diff --git a/webrtc/stats/rtcstats_unittest.cc b/webrtc/stats/rtcstats_unittest.cc index 12364aed56..44e75c41be 100644 --- a/webrtc/stats/rtcstats_unittest.cc +++ b/webrtc/stats/rtcstats_unittest.cc @@ -9,11 +9,9 @@ */ #include "webrtc/api/rtcstats.h" -#include "webrtc/api/rtcstatsreport.h" #include "webrtc/base/checks.h" #include "webrtc/base/gunit.h" -#include "webrtc/base/logging.h" namespace webrtc { @@ -165,39 +163,6 @@ TEST(RTCStatsTest, RTCStatsGrandChild) { EXPECT_EQ(*copy.grandchild_int, *stats.grandchild_int); } -TEST(RTCStatsTest, TestRTCStatsReport) { - rtc::scoped_refptr report = RTCStatsReport::Create(); - EXPECT_EQ(report->size(), static_cast(0)); - report->AddStats(std::unique_ptr(new RTCTestStats("a0", 1.0))); - report->AddStats(std::unique_ptr(new RTCTestStats("a1", 2.0))); - report->AddStats(std::unique_ptr(new RTCChildStats("b0", 4.0))); - report->AddStats(std::unique_ptr(new RTCChildStats("b1", 8.0))); - report->AddStats(std::unique_ptr(new RTCTestStats("a2", 16.0))); - report->AddStats(std::unique_ptr(new RTCChildStats("b2", 32.0))); - EXPECT_EQ(report->size(), static_cast(6)); - - EXPECT_EQ((*report)["missing"], nullptr); - EXPECT_EQ((*report)["a0"]->id(), "a0"); - EXPECT_EQ((*report)["b2"]->id(), "b2"); - - std::vector a = report->GetStatsOfType(); - EXPECT_EQ(a.size(), static_cast(3)); - uint32_t mask = 0; - for (const RTCTestStats* stats : a) - mask |= static_cast(stats->timestamp()); - EXPECT_EQ(mask, static_cast(1 | 2 | 16)); - - std::vector b = report->GetStatsOfType(); - EXPECT_EQ(b.size(), static_cast(3)); - mask = 0; - for (const RTCChildStats* stats : b) - mask |= static_cast(stats->timestamp()); - EXPECT_EQ(mask, static_cast(4 | 8 | 32)); - - EXPECT_EQ(report->GetStatsOfType().size(), - static_cast(0)); -} - // Death tests. // Disabled on Android because death tests misbehave on Android, see // base/test/gtest_util.h. diff --git a/webrtc/stats/rtcstatsreport.cc b/webrtc/stats/rtcstatsreport.cc index 870651d2df..00a55f41fc 100644 --- a/webrtc/stats/rtcstatsreport.cc +++ b/webrtc/stats/rtcstatsreport.cc @@ -66,13 +66,22 @@ bool RTCStatsReport::AddStats(std::unique_ptr stats) { std::move(stats))).second; } -const RTCStats* RTCStatsReport::operator[](const std::string& id) const { +const RTCStats* RTCStatsReport::Get(const std::string& id) const { StatsMap::const_iterator it = stats_.find(id); if (it != stats_.cend()) return it->second.get(); return nullptr; } +void RTCStatsReport::TakeMembersFrom( + rtc::scoped_refptr victim) { + for (StatsMap::iterator it = victim->stats_.begin(); + it != victim->stats_.end(); ++it) { + AddStats(std::unique_ptr(it->second.release())); + } + victim->stats_.clear(); +} + RTCStatsReport::ConstIterator RTCStatsReport::begin() const { return ConstIterator(rtc::scoped_refptr(this), stats_.cbegin()); diff --git a/webrtc/stats/rtcstatsreport_unittest.cc b/webrtc/stats/rtcstatsreport_unittest.cc new file mode 100644 index 0000000000..b4722ab156 --- /dev/null +++ b/webrtc/stats/rtcstatsreport_unittest.cc @@ -0,0 +1,131 @@ +/* + * Copyright 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/api/rtcstatsreport.h" + +#include "webrtc/api/rtcstats.h" +#include "webrtc/base/checks.h" +#include "webrtc/base/gunit.h" + +namespace webrtc { + +class RTCTestStats1 : public RTCStats { + public: + RTCTestStats1(const std::string& id, double timestamp) + : RTCStats(id, timestamp), + integer("integer") {} + + WEBRTC_RTCSTATS_IMPL(RTCStats, RTCTestStats1, + &integer); + + RTCStatsMember integer; +}; + +const char RTCTestStats1::kType[] = "test-stats-1"; + +class RTCTestStats2 : public RTCStats { + public: + RTCTestStats2(const std::string& id, double timestamp) + : RTCStats(id, timestamp), + number("number") {} + + WEBRTC_RTCSTATS_IMPL(RTCStats, RTCTestStats2, + &number); + + RTCStatsMember number; +}; + +const char RTCTestStats2::kType[] = "test-stats-2"; + +class RTCTestStats3 : public RTCStats { + public: + RTCTestStats3(const std::string& id, double timestamp) + : RTCStats(id, timestamp), + string("string") {} + + WEBRTC_RTCSTATS_IMPL(RTCStats, RTCTestStats3, + &string); + + RTCStatsMember string; +}; + +const char RTCTestStats3::kType[] = "test-stats-3"; + +TEST(RTCStatsReport, AddAndGetStats) { + rtc::scoped_refptr report = RTCStatsReport::Create(); + EXPECT_EQ(report->size(), static_cast(0)); + report->AddStats(std::unique_ptr(new RTCTestStats1("a0", 1.0))); + report->AddStats(std::unique_ptr(new RTCTestStats1("a1", 2.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("b0", 4.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("b1", 8.0))); + report->AddStats(std::unique_ptr(new RTCTestStats1("a2", 16.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("b2", 32.0))); + EXPECT_EQ(report->size(), static_cast(6)); + + EXPECT_EQ(report->Get("missing"), nullptr); + EXPECT_EQ(report->Get("a0")->id(), "a0"); + EXPECT_EQ(report->Get("b2")->id(), "b2"); + + std::vector a = report->GetStatsOfType(); + EXPECT_EQ(a.size(), static_cast(3)); + uint32_t mask = 0; + for (const RTCTestStats1* stats : a) + mask |= static_cast(stats->timestamp()); + EXPECT_EQ(mask, static_cast(1 | 2 | 16)); + + std::vector b = report->GetStatsOfType(); + EXPECT_EQ(b.size(), static_cast(3)); + mask = 0; + for (const RTCTestStats2* stats : b) + mask |= static_cast(stats->timestamp()); + EXPECT_EQ(mask, static_cast(4 | 8 | 32)); + + EXPECT_EQ(report->GetStatsOfType().size(), + static_cast(0)); +} + +TEST(RTCStatsReport, StatsOrder) { + rtc::scoped_refptr report = RTCStatsReport::Create(); + report->AddStats(std::unique_ptr(new RTCTestStats1("C", 2.0))); + report->AddStats(std::unique_ptr(new RTCTestStats1("D", 3.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("B", 1.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("A", 0.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("E", 4.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("F", 5.0))); + report->AddStats(std::unique_ptr(new RTCTestStats2("G", 6.0))); + size_t i = 0; + for (const RTCStats& stats : *report) { + EXPECT_EQ(static_cast(stats.timestamp()), i); + ++i; + } + EXPECT_EQ(i, static_cast(7)); +} + +TEST(RTCStatsReport, TakeMembersFrom) { + rtc::scoped_refptr a = RTCStatsReport::Create(); + a->AddStats(std::unique_ptr(new RTCTestStats1("B", 1.0))); + a->AddStats(std::unique_ptr(new RTCTestStats1("C", 2.0))); + a->AddStats(std::unique_ptr(new RTCTestStats1("E", 4.0))); + rtc::scoped_refptr b = RTCStatsReport::Create(); + b->AddStats(std::unique_ptr(new RTCTestStats1("A", 0.0))); + b->AddStats(std::unique_ptr(new RTCTestStats1("D", 3.0))); + b->AddStats(std::unique_ptr(new RTCTestStats1("F", 5.0))); + + a->TakeMembersFrom(b); + EXPECT_EQ(b->size(), static_cast(0)); + size_t i = 0; + for (const RTCStats& stats : *a) { + EXPECT_EQ(static_cast(stats.timestamp()), i); + ++i; + } + EXPECT_EQ(i, static_cast(6)); +} + +} // namespace webrtc diff --git a/webrtc/stats/stats.gyp b/webrtc/stats/stats.gyp index 9310aabe99..4c2255711c 100644 --- a/webrtc/stats/stats.gyp +++ b/webrtc/stats/stats.gyp @@ -37,6 +37,7 @@ ], 'sources': [ 'rtcstats_unittest.cc', + 'rtcstatsreport_unittest.cc', ], }, ],