1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/observer_list.h"
9 #include "base/logging.h"
10 #include "base/observer_list.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/time/time.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/perf/perf_test.h"
16 // Ask the compiler not to use a register for this counter, in case it decides
17 // to do magic optimizations like |counter += kLaps|.
18 volatile int g_observer_list_perf_test_counter;
22 class ObserverInterface {
24 ObserverInterface() {}
25 virtual ~ObserverInterface() {}
26 virtual void Observe() const { ++g_observer_list_perf_test_counter; }
29 DISALLOW_COPY_AND_ASSIGN(ObserverInterface);
32 class UnsafeObserver : public ObserverInterface {};
34 class TestCheckedObserver : public CheckedObserver, public ObserverInterface {};
36 template <class ObserverType>
38 // The ObserverList type to use. Checked observers need to be in a checked
40 using ObserverListType = ObserverList<ObserverType>;
41 static const char* GetName() { return "CheckedObserver"; }
44 struct Pick<UnsafeObserver> {
45 using ObserverListType = ObserverList<ObserverInterface>::Unchecked;
46 static const char* GetName() { return "UnsafeObserver"; }
49 template <class ObserverType>
50 class ObserverListPerfTest : public ::testing::Test {
52 using ObserverListType = typename Pick<ObserverType>::ObserverListType;
54 ObserverListPerfTest() {}
57 DISALLOW_COPY_AND_ASSIGN(ObserverListPerfTest);
60 typedef ::testing::Types<UnsafeObserver, TestCheckedObserver> ObserverTypes;
61 TYPED_TEST_CASE(ObserverListPerfTest, ObserverTypes);
63 // Performance test for base::ObserverList and Checked Observers.
64 TYPED_TEST(ObserverListPerfTest, NotifyPerformance) {
65 constexpr int kMaxObservers = 128;
67 // The test takes about 100x longer in debug builds, mostly due to sequence
68 // checker overheads when WeakPtr gets involved.
69 constexpr int kLaps = 1000000;
71 constexpr int kLaps = 100000000;
73 constexpr int kWarmupLaps = 100;
74 std::vector<std::unique_ptr<TypeParam>> observers;
76 for (int observer_count = 0; observer_count <= kMaxObservers;
77 observer_count = observer_count ? observer_count * 2 : 1) {
78 typename TestFixture::ObserverListType list;
79 for (int i = 0; i < observer_count; ++i)
80 observers.push_back(std::make_unique<TypeParam>());
81 for (auto& o : observers)
82 list.AddObserver(o.get());
84 for (int i = 0; i < kWarmupLaps; ++i) {
88 g_observer_list_perf_test_counter = 0;
89 const int weighted_laps = kLaps / (observer_count + 1);
91 TimeTicks start = TimeTicks::Now();
92 for (int i = 0; i < weighted_laps; ++i) {
96 TimeDelta duration = TimeTicks::Now() - start;
98 const char* name = Pick<TypeParam>::GetName();
101 EXPECT_EQ(observer_count * weighted_laps,
102 g_observer_list_perf_test_counter);
103 EXPECT_TRUE(observer_count == 0 || list.might_have_observers());
106 base::StringPrintf("ObserverListPerfTest_%d.", observer_count);
108 // A typical value is 3-20 nanoseconds per observe in Release, 1000-2000ns
109 // in an optimized build with DCHECKs and 3000-6000ns in debug builds.
110 perf_test::PrintResult(
111 prefix, name, "NotifyPerformance",
112 duration.InNanoseconds() /
113 static_cast<double>(g_observer_list_perf_test_counter +