1 // Copyright (c) 2006-2008 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 <windows.h> 6 #include <mmsystem.h> 7 #include <process.h> 8 9 #include "base/time.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 using base::Time; 13 using base::TimeDelta; 14 using base::TimeTicks; 15 16 namespace { 17 18 class MockTimeTicks : public TimeTicks { 19 public: 20 static DWORD Ticker() { 21 return static_cast<int>(InterlockedIncrement(&ticker_)); 22 } 23 24 static void InstallTicker() { 25 old_tick_function_ = SetMockTickFunction(&Ticker); 26 ticker_ = -5; 27 } 28 29 static void UninstallTicker() { 30 SetMockTickFunction(old_tick_function_); 31 } 32 33 private: 34 static volatile LONG ticker_; 35 static TickFunctionType old_tick_function_; 36 }; 37 38 volatile LONG MockTimeTicks::ticker_; 39 MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_; 40 41 HANDLE g_rollover_test_start; 42 43 unsigned __stdcall RolloverTestThreadMain(void* param) { 44 int64 counter = reinterpret_cast<int64>(param); 45 DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE); 46 EXPECT_EQ(rv, WAIT_OBJECT_0); 47 48 TimeTicks last = TimeTicks::Now(); 49 for (int index = 0; index < counter; index++) { 50 TimeTicks now = TimeTicks::Now(); 51 int64 milliseconds = (now - last).InMilliseconds(); 52 // This is a tight loop; we could have looped faster than our 53 // measurements, so the time might be 0 millis. 54 EXPECT_GE(milliseconds, 0); 55 EXPECT_LT(milliseconds, 250); 56 last = now; 57 } 58 return 0; 59 } 60 61 } // namespace 62 63 TEST(TimeTicks, WinRollover) { 64 // The internal counter rolls over at ~49days. We'll use a mock 65 // timer to test this case. 66 // Basic test algorithm: 67 // 1) Set clock to rollover - N 68 // 2) Create N threads 69 // 3) Start the threads 70 // 4) Each thread loops through TimeTicks() N times 71 // 5) Each thread verifies integrity of result. 72 73 const int kThreads = 8; 74 // Use int64 so we can cast into a void* without a compiler warning. 75 const int64 kChecks = 10; 76 77 // It takes a lot of iterations to reproduce the bug! 78 // (See bug 1081395) 79 for (int loop = 0; loop < 4096; loop++) { 80 // Setup 81 MockTimeTicks::InstallTicker(); 82 g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0); 83 HANDLE threads[kThreads]; 84 85 for (int index = 0; index < kThreads; index++) { 86 void* argument = reinterpret_cast<void*>(kChecks); 87 unsigned thread_id; 88 threads[index] = reinterpret_cast<HANDLE>( 89 _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0, 90 &thread_id)); 91 EXPECT_NE((HANDLE)NULL, threads[index]); 92 } 93 94 // Start! 95 SetEvent(g_rollover_test_start); 96 97 // Wait for threads to finish 98 for (int index = 0; index < kThreads; index++) { 99 DWORD rv = WaitForSingleObject(threads[index], INFINITE); 100 EXPECT_EQ(rv, WAIT_OBJECT_0); 101 } 102 103 CloseHandle(g_rollover_test_start); 104 105 // Teardown 106 MockTimeTicks::UninstallTicker(); 107 } 108 } 109 110 TEST(TimeTicks, SubMillisecondTimers) { 111 // Loop for a bit getting timers quickly. We want to 112 // see at least one case where we get a new sample in 113 // less than one millisecond. 114 bool saw_submillisecond_timer = false; 115 int64 min_timer = 1000; 116 TimeTicks last_time = TimeTicks::HighResNow(); 117 for (int index = 0; index < 1000; index++) { 118 TimeTicks now = TimeTicks::HighResNow(); 119 TimeDelta delta = now - last_time; 120 if (delta.InMicroseconds() > 0 && 121 delta.InMicroseconds() < 1000) { 122 if (min_timer > delta.InMicroseconds()) 123 min_timer = delta.InMicroseconds(); 124 saw_submillisecond_timer = true; 125 } 126 last_time = now; 127 } 128 EXPECT_TRUE(saw_submillisecond_timer); 129 printf("Min timer is: %ldus\n", static_cast<long>(min_timer)); 130 } 131 132 TEST(TimeTicks, TimeGetTimeCaps) { 133 // Test some basic assumptions that we expect about how timeGetDevCaps works. 134 135 TIMECAPS caps; 136 MMRESULT status = timeGetDevCaps(&caps, sizeof(caps)); 137 EXPECT_EQ(TIMERR_NOERROR, status); 138 if (status != TIMERR_NOERROR) { 139 printf("Could not get timeGetDevCaps\n"); 140 return; 141 } 142 143 EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1); 144 EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1); 145 EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1); 146 EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1); 147 printf("timeGetTime range is %d to %dms\n", caps.wPeriodMin, 148 caps.wPeriodMax); 149 } 150 151 TEST(TimeTicks, QueryPerformanceFrequency) { 152 // Test some basic assumptions that we expect about QPC. 153 154 LARGE_INTEGER frequency; 155 BOOL rv = QueryPerformanceFrequency(&frequency); 156 EXPECT_EQ(TRUE, rv); 157 EXPECT_GT(frequency.QuadPart, 1000000); // Expect at least 1MHz 158 printf("QueryPerformanceFrequency is %5.2fMHz\n", 159 frequency.QuadPart / 1000000.0); 160 } 161 162 TEST(TimeTicks, TimerPerformance) { 163 // Verify that various timer mechanisms can always complete quickly. 164 // Note: This is a somewhat arbitrary test. 165 const int kLoops = 10000; 166 // Due to the fact that these run on bbots, which are horribly slow, 167 // we can't really make any guarantees about minimum runtime. 168 // Really, we want these to finish in ~10ms, and that is generous. 169 const int kMaxTime = 35; // Maximum acceptible milliseconds for test. 170 171 typedef TimeTicks (*TestFunc)(); 172 struct TestCase { 173 TestFunc func; 174 char *description; 175 }; 176 // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time) 177 // in order to create a single test case list. 178 COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time), 179 test_only_works_with_same_sizes); 180 TestCase cases[] = { 181 { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" }, 182 { TimeTicks::Now, "TimeTicks::Now" }, 183 { TimeTicks::HighResNow, "TimeTicks::HighResNow" }, 184 { NULL, "" } 185 }; 186 187 int test_case = 0; 188 while (cases[test_case].func) { 189 TimeTicks start = TimeTicks::HighResNow(); 190 for (int index = 0; index < kLoops; index++) 191 cases[test_case].func(); 192 TimeTicks stop = TimeTicks::HighResNow(); 193 // Turning off the check for acceptible delays. Without this check, 194 // the test really doesn't do much other than measure. But the 195 // measurements are still useful for testing timers on various platforms. 196 // The reason to remove the check is because the tests run on many 197 // buildbots, some of which are VMs. These machines can run horribly 198 // slow, and there is really no value for checking against a max timer. 199 //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime); 200 printf("%s: %1.2fus per call\n", cases[test_case].description, 201 (stop - start).InMillisecondsF() * 1000 / kLoops); 202 test_case++; 203 } 204 } 205