123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/observer_list.h"
- #include <memory>
- #include "base/check_op.h"
- #include "base/strings/stringprintf.h"
- #include "base/time/time.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/perf/perf_result_reporter.h"
- // Ask the compiler not to use a register for this counter, in case it decides
- // to do magic optimizations like |counter += kLaps|.
- volatile int g_observer_list_perf_test_counter;
- namespace base {
- constexpr char kMetricPrefixObserverList[] = "ObserverList.";
- constexpr char kMetricNotifyTimePerObserver[] = "notify_time_per_observer";
- namespace {
- perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
- perf_test::PerfResultReporter reporter(kMetricPrefixObserverList, story_name);
- reporter.RegisterImportantMetric(kMetricNotifyTimePerObserver, "ns");
- return reporter;
- }
- } // namespace
- class ObserverInterface {
- public:
- ObserverInterface() = default;
- ObserverInterface(const ObserverInterface&) = delete;
- ObserverInterface& operator=(const ObserverInterface&) = delete;
- virtual ~ObserverInterface() = default;
- virtual void Observe() const {
- g_observer_list_perf_test_counter = g_observer_list_perf_test_counter + 1;
- }
- };
- class UnsafeObserver : public ObserverInterface {};
- class TestCheckedObserver : public CheckedObserver, public ObserverInterface {};
- template <class ObserverType>
- struct Pick {
- // The ObserverList type to use. Checked observers need to be in a checked
- // ObserverList.
- using ObserverListType = ObserverList<ObserverType>;
- static const char* GetName() { return "CheckedObserver"; }
- };
- template <>
- struct Pick<UnsafeObserver> {
- using ObserverListType = ObserverList<ObserverInterface>::Unchecked;
- static const char* GetName() { return "UnsafeObserver"; }
- };
- template <class ObserverType>
- class ObserverListPerfTest : public ::testing::Test {
- public:
- using ObserverListType = typename Pick<ObserverType>::ObserverListType;
- ObserverListPerfTest() = default;
- ObserverListPerfTest(const ObserverListPerfTest&) = delete;
- ObserverListPerfTest& operator=(const ObserverListPerfTest&) = delete;
- };
- typedef ::testing::Types<UnsafeObserver, TestCheckedObserver> ObserverTypes;
- TYPED_TEST_SUITE(ObserverListPerfTest, ObserverTypes);
- // Performance test for base::ObserverList and Checked Observers.
- TYPED_TEST(ObserverListPerfTest, NotifyPerformance) {
- constexpr int kMaxObservers = 128;
- #if DCHECK_IS_ON()
- // The test takes about 100x longer in debug builds, mostly due to sequence
- // checker overheads when WeakPtr gets involved.
- constexpr int kLaps = 1000000;
- #else
- constexpr int kLaps = 100000000;
- #endif
- constexpr int kWarmupLaps = 100;
- std::vector<std::unique_ptr<TypeParam>> observers;
- for (int observer_count = 0; observer_count <= kMaxObservers;
- observer_count = observer_count ? observer_count * 2 : 1) {
- typename TestFixture::ObserverListType list;
- for (int i = 0; i < observer_count; ++i)
- observers.push_back(std::make_unique<TypeParam>());
- for (auto& o : observers)
- list.AddObserver(o.get());
- for (int i = 0; i < kWarmupLaps; ++i) {
- for (auto& o : list)
- o.Observe();
- }
- g_observer_list_perf_test_counter = 0;
- const int weighted_laps = kLaps / (observer_count + 1);
- TimeTicks start = TimeTicks::Now();
- for (int i = 0; i < weighted_laps; ++i) {
- for (auto& o : list)
- o.Observe();
- }
- TimeDelta duration = TimeTicks::Now() - start;
- observers.clear();
- EXPECT_EQ(observer_count * weighted_laps,
- g_observer_list_perf_test_counter);
- EXPECT_TRUE(observer_count == 0 || !list.empty());
- std::string story_name =
- base::StringPrintf("%s_%d", Pick<TypeParam>::GetName(), observer_count);
- // A typical value is 3-20 nanoseconds per observe in Release, 1000-2000ns
- // in an optimized build with DCHECKs and 3000-6000ns in debug builds.
- auto reporter = SetUpReporter(story_name);
- reporter.AddResult(
- kMetricNotifyTimePerObserver,
- duration.InNanoseconds() /
- static_cast<double>(g_observer_list_perf_test_counter +
- weighted_laps));
- }
- }
- } // namespace base
|