1 // Copyright 2016 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.
4
5 #include "components/subresource_filter/core/common/scoped_timers.h"
6
7 #include "base/test/metrics/histogram_tester.h"
8 #include "base/time/time.h"
9 #include "components/subresource_filter/core/common/time_measurements.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace {
13
14 class MockExportFunctor {
15 public:
number_of_calls() const16 int number_of_calls() const { return number_of_calls_; }
operator ()(base::TimeDelta)17 void operator()(base::TimeDelta) { ++number_of_calls_; }
18
19 private:
20 int number_of_calls_ = 0;
21 };
22
23 template <typename TimerFactory>
ExpectFunctorIsCalledOnceOnDestruction()24 void ExpectFunctorIsCalledOnceOnDestruction() {
25 MockExportFunctor export_functor;
26 {
27 auto scoped_timer = TimerFactory::Start(export_functor);
28 EXPECT_EQ(0, export_functor.number_of_calls());
29 }
30 const int expected_number_of_calls = TimerFactory::IsSupported() ? 1 : 0;
31 EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls());
32 }
33
34 template <typename TimerFactory>
ExpectStoredLambdaIsInvokedOnceOnDestruction()35 void ExpectStoredLambdaIsInvokedOnceOnDestruction() {
36 bool export_is_called = false;
37 auto export_functor = [&export_is_called](base::TimeDelta) {
38 EXPECT_FALSE(export_is_called);
39 export_is_called = true;
40 };
41
42 {
43 auto scoped_timer = TimerFactory::Start(export_functor);
44 EXPECT_FALSE(export_is_called);
45 }
46 EXPECT_EQ(TimerFactory::IsSupported(), export_is_called);
47 }
48
49 template <typename TimerFactory>
ExpectInlineLambdaIsInvokedOnceOnDestruction()50 void ExpectInlineLambdaIsInvokedOnceOnDestruction() {
51 bool export_is_called = false;
52 {
53 auto scoped_timer =
54 TimerFactory::Start([&export_is_called](base::TimeDelta) {
55 EXPECT_FALSE(export_is_called);
56 export_is_called = true;
57 });
58 EXPECT_FALSE(export_is_called);
59 }
60 EXPECT_EQ(TimerFactory::IsSupported(), export_is_called);
61 }
62
63 template <typename TimerFactory>
ExpectWellBehavedStartIf(bool condition)64 void ExpectWellBehavedStartIf(bool condition) {
65 bool export_is_called = false;
66 auto export_functor = [&export_is_called](base::TimeDelta) {
67 EXPECT_FALSE(export_is_called);
68 export_is_called = true;
69 };
70
71 {
72 auto scoped_timer = TimerFactory::StartIf(condition, export_functor);
73 EXPECT_FALSE(export_is_called);
74 }
75 EXPECT_EQ(condition && TimerFactory::IsSupported(), export_is_called);
76 }
77
78 template <typename TimerFactory>
ExpectWellBehavedMoveContructor()79 void ExpectWellBehavedMoveContructor() {
80 MockExportFunctor export_functor;
81 const int expected_number_of_calls = TimerFactory::IsSupported() ? 1 : 0;
82 {
83 auto scoped_timer = TimerFactory::Start(export_functor);
84 EXPECT_EQ(0, export_functor.number_of_calls());
85 {
86 auto another_scoped_timer = std::move(scoped_timer);
87 EXPECT_EQ(0, export_functor.number_of_calls());
88 }
89 // |another_scoped_timer| should have called |export_functor|.
90 EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls());
91 }
92 // But |scoped_timer| should have not since then.
93 EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls());
94 }
95
96 template <typename TimerFactory>
ExpectWellBehavedMoveAssignment()97 void ExpectWellBehavedMoveAssignment() {
98 MockExportFunctor export_functor;
99 const int expected_number_of_calls = TimerFactory::IsSupported() ? 1 : 0;
100 {
101 auto scoped_timer = TimerFactory::Start(export_functor);
102 EXPECT_EQ(0, export_functor.number_of_calls());
103 {
104 auto another_scoped_timer = std::move(scoped_timer);
105 scoped_timer = std::move(another_scoped_timer);
106 EXPECT_EQ(0, export_functor.number_of_calls());
107 }
108 // |another_scoped_timer| shouldn't have called |export_functor|.
109 EXPECT_EQ(0, export_functor.number_of_calls());
110 }
111 // But |scoped_timer| should have because it owns the measurement.
112 EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls());
113 }
114
115 } // namespace
116
117 namespace subresource_filter {
118
TEST(ScopedTimersTest,CallsFunctor)119 TEST(ScopedTimersTest, CallsFunctor) {
120 ExpectFunctorIsCalledOnceOnDestruction<ScopedTimers>();
121 ExpectFunctorIsCalledOnceOnDestruction<ScopedThreadTimers>();
122 }
123
TEST(ScopedTimersTest,CallsStoredLambdaFunctor)124 TEST(ScopedTimersTest, CallsStoredLambdaFunctor) {
125 ExpectStoredLambdaIsInvokedOnceOnDestruction<ScopedTimers>();
126 ExpectStoredLambdaIsInvokedOnceOnDestruction<ScopedThreadTimers>();
127 }
128
TEST(ScopedTimersTest,CallsInlineLambdaFunctor)129 TEST(ScopedTimersTest, CallsInlineLambdaFunctor) {
130 ExpectInlineLambdaIsInvokedOnceOnDestruction<ScopedTimers>();
131 ExpectInlineLambdaIsInvokedOnceOnDestruction<ScopedThreadTimers>();
132 }
133
TEST(ScopedTimersTest,StartIf)134 TEST(ScopedTimersTest, StartIf) {
135 ExpectWellBehavedStartIf<ScopedTimers>(false);
136 ExpectWellBehavedStartIf<ScopedTimers>(true);
137
138 ExpectWellBehavedStartIf<ScopedThreadTimers>(false);
139 ExpectWellBehavedStartIf<ScopedThreadTimers>(true);
140 }
141
TEST(ScopedTimersTest,MoveConstructTimer)142 TEST(ScopedTimersTest, MoveConstructTimer) {
143 ExpectWellBehavedMoveContructor<ScopedTimers>();
144 ExpectWellBehavedMoveContructor<ScopedThreadTimers>();
145 }
146
TEST(ScopedTimersTest,MoveAssignTimer)147 TEST(ScopedTimersTest, MoveAssignTimer) {
148 ExpectWellBehavedMoveAssignment<ScopedTimers>();
149 ExpectWellBehavedMoveAssignment<ScopedThreadTimers>();
150 }
151
152 // Below are tests for macros in "time_measurements.h" -------------------------
153 // TODO(pkalinnikov): Move these to a separate file?
154
TEST(ScopedTimersTest,ScopedUmaHistogramMacros)155 TEST(ScopedTimersTest, ScopedUmaHistogramMacros) {
156 base::HistogramTester tester;
157 {
158 SCOPED_UMA_HISTOGRAM_THREAD_TIMER("ScopedTimers.ThreadTimer");
159 SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER("ScopedTimers.MicroThreadTimer");
160 SCOPED_UMA_HISTOGRAM_MICRO_TIMER("ScopedTimers.MicroTimer");
161
162 tester.ExpectTotalCount("ScopedTimers.ThreadTimer", 0);
163 tester.ExpectTotalCount("ScopedTimers.MicroThreadTimer", 0);
164 tester.ExpectTotalCount("ScopedTimers.MicroTimer", 0);
165 }
166
167 int expected_count = ScopedTimers::IsSupported() ? 1 : 0;
168 tester.ExpectTotalCount("ScopedTimers.MicroTimer", expected_count);
169
170 expected_count = ScopedThreadTimers::IsSupported() ? 1 : 0;
171 tester.ExpectTotalCount("ScopedTimers.ThreadTimer", expected_count);
172 tester.ExpectTotalCount("ScopedTimers.MicroThreadTimer", expected_count);
173 }
174
TEST(ScopedTimersTest,UmaHistogramMicroTimesFromExportFunctor)175 TEST(ScopedTimersTest, UmaHistogramMicroTimesFromExportFunctor) {
176 base::HistogramTester tester;
177 auto export_functor = [](base::TimeDelta delta) {
178 UMA_HISTOGRAM_MICRO_TIMES("ScopedTimers.MicroTimes", delta);
179 };
180 {
181 auto scoped_timer = ScopedTimers::Start(export_functor);
182 tester.ExpectTotalCount("ScopedTimers.MicroTimes", 0);
183 }
184 tester.ExpectTotalCount("ScopedTimers.MicroTimes", 1);
185 }
186
187 } // namespace subresource_filter
188