Android: remove device_data.h from browser/device_orientation/
[chromium-blink-merge.git] / base / metrics / stats_table_unittest.cc
blob8fd33971f4f1c595b2d5258b32e6fd0619d38aa0
1 // Copyright (c) 2012 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/memory/shared_memory.h"
6 #include "base/metrics/stats_counters.h"
7 #include "base/metrics/stats_table.h"
8 #include "base/process/kill.h"
9 #include "base/strings/string_piece.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/test/multiprocess_test.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/simple_thread.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/multiprocess_func_list.h"
18 namespace base {
20 class StatsTableTest : public MultiProcessTest {
21 public:
22 void DeleteShmem(const std::string& name) {
23 SharedMemory mem;
24 mem.Delete(name);
28 // Open a StatsTable and verify that we can write to each of the
29 // locations in the table.
30 TEST_F(StatsTableTest, VerifySlots) {
31 const std::string kTableName = "VerifySlotsStatTable";
32 const int kMaxThreads = 1;
33 const int kMaxCounter = 5;
34 DeleteShmem(kTableName);
35 StatsTable table(kTableName, kMaxThreads, kMaxCounter);
37 // Register a single thread.
38 std::string thread_name = "mainThread";
39 int slot_id = table.RegisterThread(thread_name);
40 EXPECT_NE(slot_id, 0);
42 // Fill up the table with counters.
43 std::string counter_base_name = "counter";
44 for (int index = 0; index < kMaxCounter; index++) {
45 std::string counter_name = counter_base_name;
46 base::StringAppendF(&counter_name, "counter.ctr%d", index);
47 int counter_id = table.FindCounter(counter_name);
48 EXPECT_GT(counter_id, 0);
51 // Try to allocate an additional thread. Verify it fails.
52 slot_id = table.RegisterThread("too many threads");
53 EXPECT_EQ(slot_id, 0);
55 // Try to allocate an additional counter. Verify it fails.
56 int counter_id = table.FindCounter(counter_base_name);
57 EXPECT_EQ(counter_id, 0);
59 DeleteShmem(kTableName);
62 // CounterZero will continually be set to 0.
63 const std::string kCounterZero = "CounterZero";
64 // Counter1313 will continually be set to 1313.
65 const std::string kCounter1313 = "Counter1313";
66 // CounterIncrement will be incremented each time.
67 const std::string kCounterIncrement = "CounterIncrement";
68 // CounterDecrement will be decremented each time.
69 const std::string kCounterDecrement = "CounterDecrement";
70 // CounterMixed will be incremented by odd numbered threads and
71 // decremented by even threads.
72 const std::string kCounterMixed = "CounterMixed";
73 // The number of thread loops that we will do.
74 const int kThreadLoops = 100;
76 class StatsTableThread : public SimpleThread {
77 public:
78 StatsTableThread(std::string name, int id)
79 : SimpleThread(name),
80 id_(id) {}
82 virtual void Run() OVERRIDE;
84 private:
85 int id_;
88 void StatsTableThread::Run() {
89 // Each thread will open the shared memory and set counters
90 // concurrently in a loop. We'll use some pauses to
91 // mixup the thread scheduling.
93 StatsCounter zero_counter(kCounterZero);
94 StatsCounter lucky13_counter(kCounter1313);
95 StatsCounter increment_counter(kCounterIncrement);
96 StatsCounter decrement_counter(kCounterDecrement);
97 for (int index = 0; index < kThreadLoops; index++) {
98 StatsCounter mixed_counter(kCounterMixed); // create this one in the loop
99 zero_counter.Set(0);
100 lucky13_counter.Set(1313);
101 increment_counter.Increment();
102 decrement_counter.Decrement();
103 if (id_ % 2)
104 mixed_counter.Decrement();
105 else
106 mixed_counter.Increment();
107 PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
111 // Create a few threads and have them poke on their counters.
112 // See http://crbug.com/10611 for more information.
113 #if defined(OS_MACOSX) || defined(THREAD_SANITIZER)
114 #define MAYBE_MultipleThreads DISABLED_MultipleThreads
115 #else
116 #define MAYBE_MultipleThreads MultipleThreads
117 #endif
118 TEST_F(StatsTableTest, MAYBE_MultipleThreads) {
119 // Create a stats table.
120 const std::string kTableName = "MultipleThreadStatTable";
121 const int kMaxThreads = 20;
122 const int kMaxCounter = 5;
123 DeleteShmem(kTableName);
124 StatsTable table(kTableName, kMaxThreads, kMaxCounter);
125 StatsTable::set_current(&table);
127 EXPECT_EQ(0, table.CountThreadsRegistered());
129 // Spin up a set of threads to go bang on the various counters.
130 // After we join the threads, we'll make sure the counters
131 // contain the values we expected.
132 StatsTableThread* threads[kMaxThreads];
134 // Spawn the threads.
135 for (int index = 0; index < kMaxThreads; index++) {
136 threads[index] = new StatsTableThread("MultipleThreadsTest", index);
137 threads[index]->Start();
140 // Wait for the threads to finish.
141 for (int index = 0; index < kMaxThreads; index++) {
142 threads[index]->Join();
143 delete threads[index];
146 StatsCounter zero_counter(kCounterZero);
147 StatsCounter lucky13_counter(kCounter1313);
148 StatsCounter increment_counter(kCounterIncrement);
149 StatsCounter decrement_counter(kCounterDecrement);
150 StatsCounter mixed_counter(kCounterMixed);
152 // Verify the various counters are correct.
153 std::string name;
154 name = "c:" + kCounterZero;
155 EXPECT_EQ(0, table.GetCounterValue(name));
156 name = "c:" + kCounter1313;
157 EXPECT_EQ(1313 * kMaxThreads,
158 table.GetCounterValue(name));
159 name = "c:" + kCounterIncrement;
160 EXPECT_EQ(kMaxThreads * kThreadLoops,
161 table.GetCounterValue(name));
162 name = "c:" + kCounterDecrement;
163 EXPECT_EQ(-kMaxThreads * kThreadLoops,
164 table.GetCounterValue(name));
165 name = "c:" + kCounterMixed;
166 EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
167 table.GetCounterValue(name));
168 EXPECT_EQ(0, table.CountThreadsRegistered());
170 DeleteShmem(kTableName);
173 const std::string kMPTableName = "MultipleProcessStatTable";
175 MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
176 // Each process will open the shared memory and set counters
177 // concurrently in a loop. We'll use some pauses to
178 // mixup the scheduling.
180 StatsTable table(kMPTableName, 0, 0);
181 StatsTable::set_current(&table);
182 StatsCounter zero_counter(kCounterZero);
183 StatsCounter lucky13_counter(kCounter1313);
184 StatsCounter increment_counter(kCounterIncrement);
185 StatsCounter decrement_counter(kCounterDecrement);
186 for (int index = 0; index < kThreadLoops; index++) {
187 zero_counter.Set(0);
188 lucky13_counter.Set(1313);
189 increment_counter.Increment();
190 decrement_counter.Decrement();
191 PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
193 return 0;
196 // Create a few processes and have them poke on their counters.
197 // This test is slow and flaky http://crbug.com/10611
198 TEST_F(StatsTableTest, DISABLED_MultipleProcesses) {
199 // Create a stats table.
200 const int kMaxProcs = 20;
201 const int kMaxCounter = 5;
202 DeleteShmem(kMPTableName);
203 StatsTable table(kMPTableName, kMaxProcs, kMaxCounter);
204 StatsTable::set_current(&table);
205 EXPECT_EQ(0, table.CountThreadsRegistered());
207 // Spin up a set of processes to go bang on the various counters.
208 // After we join the processes, we'll make sure the counters
209 // contain the values we expected.
210 ProcessHandle procs[kMaxProcs];
212 // Spawn the processes.
213 for (int16 index = 0; index < kMaxProcs; index++) {
214 procs[index] = this->SpawnChild("StatsTableMultipleProcessMain", false);
215 EXPECT_NE(kNullProcessHandle, procs[index]);
218 // Wait for the processes to finish.
219 for (int index = 0; index < kMaxProcs; index++) {
220 EXPECT_TRUE(WaitForSingleProcess(
221 procs[index], base::TimeDelta::FromMinutes(1)));
222 CloseProcessHandle(procs[index]);
225 StatsCounter zero_counter(kCounterZero);
226 StatsCounter lucky13_counter(kCounter1313);
227 StatsCounter increment_counter(kCounterIncrement);
228 StatsCounter decrement_counter(kCounterDecrement);
230 // Verify the various counters are correct.
231 std::string name;
232 name = "c:" + kCounterZero;
233 EXPECT_EQ(0, table.GetCounterValue(name));
234 name = "c:" + kCounter1313;
235 EXPECT_EQ(1313 * kMaxProcs,
236 table.GetCounterValue(name));
237 name = "c:" + kCounterIncrement;
238 EXPECT_EQ(kMaxProcs * kThreadLoops,
239 table.GetCounterValue(name));
240 name = "c:" + kCounterDecrement;
241 EXPECT_EQ(-kMaxProcs * kThreadLoops,
242 table.GetCounterValue(name));
243 EXPECT_EQ(0, table.CountThreadsRegistered());
245 DeleteShmem(kMPTableName);
248 class MockStatsCounter : public StatsCounter {
249 public:
250 explicit MockStatsCounter(const std::string& name)
251 : StatsCounter(name) {}
252 int* Pointer() { return GetPtr(); }
255 // Test some basic StatsCounter operations
256 TEST_F(StatsTableTest, StatsCounter) {
257 // Create a stats table.
258 const std::string kTableName = "StatTable";
259 const int kMaxThreads = 20;
260 const int kMaxCounter = 5;
261 DeleteShmem(kTableName);
262 StatsTable table(kTableName, kMaxThreads, kMaxCounter);
263 StatsTable::set_current(&table);
265 MockStatsCounter foo("foo");
267 // Test initial state.
268 EXPECT_TRUE(foo.Enabled());
269 ASSERT_NE(foo.Pointer(), static_cast<int*>(0));
270 EXPECT_EQ(0, *(foo.Pointer()));
271 EXPECT_EQ(0, table.GetCounterValue("c:foo"));
273 // Test Increment.
274 while (*(foo.Pointer()) < 123) foo.Increment();
275 EXPECT_EQ(123, table.GetCounterValue("c:foo"));
276 foo.Add(0);
277 EXPECT_EQ(123, table.GetCounterValue("c:foo"));
278 foo.Add(-1);
279 EXPECT_EQ(122, table.GetCounterValue("c:foo"));
281 // Test Set.
282 foo.Set(0);
283 EXPECT_EQ(0, table.GetCounterValue("c:foo"));
284 foo.Set(100);
285 EXPECT_EQ(100, table.GetCounterValue("c:foo"));
286 foo.Set(-1);
287 EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
288 foo.Set(0);
289 EXPECT_EQ(0, table.GetCounterValue("c:foo"));
291 // Test Decrement.
292 foo.Subtract(1);
293 EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
294 foo.Subtract(0);
295 EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
296 foo.Subtract(-1);
297 EXPECT_EQ(0, table.GetCounterValue("c:foo"));
299 DeleteShmem(kTableName);
302 class MockStatsCounterTimer : public StatsCounterTimer {
303 public:
304 explicit MockStatsCounterTimer(const std::string& name)
305 : StatsCounterTimer(name) {}
307 TimeTicks start_time() { return start_time_; }
308 TimeTicks stop_time() { return stop_time_; }
311 // Test some basic StatsCounterTimer operations
312 TEST_F(StatsTableTest, StatsCounterTimer) {
313 // Create a stats table.
314 const std::string kTableName = "StatTable";
315 const int kMaxThreads = 20;
316 const int kMaxCounter = 5;
317 DeleteShmem(kTableName);
318 StatsTable table(kTableName, kMaxThreads, kMaxCounter);
319 StatsTable::set_current(&table);
321 MockStatsCounterTimer bar("bar");
323 // Test initial state.
324 EXPECT_FALSE(bar.Running());
325 EXPECT_TRUE(bar.start_time().is_null());
326 EXPECT_TRUE(bar.stop_time().is_null());
328 const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
330 // Do some timing.
331 bar.Start();
332 PlatformThread::Sleep(kDuration);
333 bar.Stop();
334 EXPECT_GT(table.GetCounterValue("t:bar"), 0);
335 EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
337 // Verify that timing again is additive.
338 bar.Start();
339 PlatformThread::Sleep(kDuration);
340 bar.Stop();
341 EXPECT_GT(table.GetCounterValue("t:bar"), 0);
342 EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
343 DeleteShmem(kTableName);
346 // Test some basic StatsRate operations
347 TEST_F(StatsTableTest, StatsRate) {
348 // Create a stats table.
349 const std::string kTableName = "StatTable";
350 const int kMaxThreads = 20;
351 const int kMaxCounter = 5;
352 DeleteShmem(kTableName);
353 StatsTable table(kTableName, kMaxThreads, kMaxCounter);
354 StatsTable::set_current(&table);
356 StatsRate baz("baz");
358 // Test initial state.
359 EXPECT_FALSE(baz.Running());
360 EXPECT_EQ(0, table.GetCounterValue("c:baz"));
361 EXPECT_EQ(0, table.GetCounterValue("t:baz"));
363 const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
365 // Do some timing.
366 baz.Start();
367 PlatformThread::Sleep(kDuration);
368 baz.Stop();
369 EXPECT_EQ(1, table.GetCounterValue("c:baz"));
370 EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:baz"));
372 // Verify that timing again is additive.
373 baz.Start();
374 PlatformThread::Sleep(kDuration);
375 baz.Stop();
376 EXPECT_EQ(2, table.GetCounterValue("c:baz"));
377 EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:baz"));
378 DeleteShmem(kTableName);
381 // Test some basic StatsScope operations
382 TEST_F(StatsTableTest, StatsScope) {
383 // Create a stats table.
384 const std::string kTableName = "StatTable";
385 const int kMaxThreads = 20;
386 const int kMaxCounter = 5;
387 DeleteShmem(kTableName);
388 StatsTable table(kTableName, kMaxThreads, kMaxCounter);
389 StatsTable::set_current(&table);
391 StatsCounterTimer foo("foo");
392 StatsRate bar("bar");
394 // Test initial state.
395 EXPECT_EQ(0, table.GetCounterValue("t:foo"));
396 EXPECT_EQ(0, table.GetCounterValue("t:bar"));
397 EXPECT_EQ(0, table.GetCounterValue("c:bar"));
399 const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
401 // Try a scope.
403 StatsScope<StatsCounterTimer> timer(foo);
404 StatsScope<StatsRate> timer2(bar);
405 PlatformThread::Sleep(kDuration);
407 EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:foo"));
408 EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
409 EXPECT_EQ(1, table.GetCounterValue("c:bar"));
411 // Try a second scope.
413 StatsScope<StatsCounterTimer> timer(foo);
414 StatsScope<StatsRate> timer2(bar);
415 PlatformThread::Sleep(kDuration);
417 EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:foo"));
418 EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
419 EXPECT_EQ(2, table.GetCounterValue("c:bar"));
421 DeleteShmem(kTableName);
424 } // namespace base