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. 4 5#include <windows.h> 6#include <mmsystem.h> 7#include <process.h> 8 9#include "base/threading/platform_thread.h" 10#include "base/time/time.h" 11#include "testing/gtest/include/gtest/gtest.h" 12 13using base::Time; 14using base::TimeDelta; 15using base::TimeTicks; 16 17namespace { 18 19class MockTimeTicks : public TimeTicks { 20 public: 21 static DWORD Ticker() { 22 return static_cast<int>(InterlockedIncrement(&ticker_)); 23 } 24 25 static void InstallTicker() { 26 old_tick_function_ = SetMockTickFunction(&Ticker); 27 ticker_ = -5; 28 } 29 30 static void UninstallTicker() { 31 SetMockTickFunction(old_tick_function_); 32 } 33 34 private: 35 static volatile LONG ticker_; 36 static TickFunctionType old_tick_function_; 37}; 38 39volatile LONG MockTimeTicks::ticker_; 40MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_; 41 42HANDLE g_rollover_test_start; 43 44unsigned __stdcall RolloverTestThreadMain(void* param) { 45 int64 counter = reinterpret_cast<int64>(param); 46 DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE); 47 EXPECT_EQ(rv, WAIT_OBJECT_0); 48 49 TimeTicks last = TimeTicks::Now(); 50 for (int index = 0; index < counter; index++) { 51 TimeTicks now = TimeTicks::Now(); 52 int64 milliseconds = (now - last).InMilliseconds(); 53 // This is a tight loop; we could have looped faster than our 54 // measurements, so the time might be 0 millis. 55 EXPECT_GE(milliseconds, 0); 56 EXPECT_LT(milliseconds, 250); 57 last = now; 58 } 59 return 0; 60} 61 62} // namespace 63 64TEST(TimeTicks, WinRollover) { 65 // The internal counter rolls over at ~49days. We'll use a mock 66 // timer to test this case. 67 // Basic test algorithm: 68 // 1) Set clock to rollover - N 69 // 2) Create N threads 70 // 3) Start the threads 71 // 4) Each thread loops through TimeTicks() N times 72 // 5) Each thread verifies integrity of result. 73 74 const int kThreads = 8; 75 // Use int64 so we can cast into a void* without a compiler warning. 76 const int64 kChecks = 10; 77 78 // It takes a lot of iterations to reproduce the bug! 79 // (See bug 1081395) 80 for (int loop = 0; loop < 4096; loop++) { 81 // Setup 82 MockTimeTicks::InstallTicker(); 83 g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0); 84 HANDLE threads[kThreads]; 85 86 for (int index = 0; index < kThreads; index++) { 87 void* argument = reinterpret_cast<void*>(kChecks); 88 unsigned thread_id; 89 threads[index] = reinterpret_cast<HANDLE>( 90 _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0, 91 &thread_id)); 92 EXPECT_NE((HANDLE)NULL, threads[index]); 93 } 94 95 // Start! 96 SetEvent(g_rollover_test_start); 97 98 // Wait for threads to finish 99 for (int index = 0; index < kThreads; index++) { 100 DWORD rv = WaitForSingleObject(threads[index], INFINITE); 101 EXPECT_EQ(rv, WAIT_OBJECT_0); 102 // Since using _beginthreadex() (as opposed to _beginthread), 103 // an explicit CloseHandle() is supposed to be called. 104 CloseHandle(threads[index]); 105 } 106 107 CloseHandle(g_rollover_test_start); 108 109 // Teardown 110 MockTimeTicks::UninstallTicker(); 111 } 112} 113 114TEST(TimeTicks, SubMillisecondTimers) { 115 // HighResNow doesn't work on some systems. Since the product still works 116 // even if it doesn't work, it makes this entire test questionable. 117 if (!TimeTicks::IsHighResClockWorking()) 118 return; 119 120 const int kRetries = 1000; 121 bool saw_submillisecond_timer = false; 122 123 // Run kRetries attempts to see a sub-millisecond timer. 124 for (int index = 0; index < 1000; index++) { 125 TimeTicks last_time = TimeTicks::HighResNow(); 126 TimeDelta delta; 127 // Spin until the clock has detected a change. 128 do { 129 delta = TimeTicks::HighResNow() - last_time; 130 } while (delta.InMicroseconds() == 0); 131 if (delta.InMicroseconds() < 1000) { 132 saw_submillisecond_timer = true; 133 break; 134 } 135 } 136 EXPECT_TRUE(saw_submillisecond_timer); 137} 138 139TEST(TimeTicks, TimeGetTimeCaps) { 140 // Test some basic assumptions that we expect about how timeGetDevCaps works. 141 142 TIMECAPS caps; 143 MMRESULT status = timeGetDevCaps(&caps, sizeof(caps)); 144 EXPECT_EQ(TIMERR_NOERROR, status); 145 if (status != TIMERR_NOERROR) { 146 printf("Could not get timeGetDevCaps\n"); 147 return; 148 } 149 150 EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1); 151 EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1); 152 EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1); 153 EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1); 154 printf("timeGetTime range is %d to %dms\n", caps.wPeriodMin, 155 caps.wPeriodMax); 156} 157 158TEST(TimeTicks, QueryPerformanceFrequency) { 159 // Test some basic assumptions that we expect about QPC. 160 161 LARGE_INTEGER frequency; 162 BOOL rv = QueryPerformanceFrequency(&frequency); 163 EXPECT_EQ(TRUE, rv); 164 EXPECT_GT(frequency.QuadPart, 1000000); // Expect at least 1MHz 165 printf("QueryPerformanceFrequency is %5.2fMHz\n", 166 frequency.QuadPart / 1000000.0); 167} 168 169TEST(TimeTicks, TimerPerformance) { 170 // Verify that various timer mechanisms can always complete quickly. 171 // Note: This is a somewhat arbitrary test. 172 const int kLoops = 10000; 173 // Due to the fact that these run on bbots, which are horribly slow, 174 // we can't really make any guarantees about minimum runtime. 175 // Really, we want these to finish in ~10ms, and that is generous. 176 const int kMaxTime = 35; // Maximum acceptible milliseconds for test. 177 178 typedef TimeTicks (*TestFunc)(); 179 struct TestCase { 180 TestFunc func; 181 const char *description; 182 }; 183 // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time) 184 // in order to create a single test case list. 185 COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time), 186 test_only_works_with_same_sizes); 187 TestCase cases[] = { 188 { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" }, 189 { TimeTicks::Now, "TimeTicks::Now" }, 190 { TimeTicks::HighResNow, "TimeTicks::HighResNow" }, 191 { NULL, "" } 192 }; 193 194 int test_case = 0; 195 while (cases[test_case].func) { 196 TimeTicks start = TimeTicks::HighResNow(); 197 for (int index = 0; index < kLoops; index++) 198 cases[test_case].func(); 199 TimeTicks stop = TimeTicks::HighResNow(); 200 // Turning off the check for acceptible delays. Without this check, 201 // the test really doesn't do much other than measure. But the 202 // measurements are still useful for testing timers on various platforms. 203 // The reason to remove the check is because the tests run on many 204 // buildbots, some of which are VMs. These machines can run horribly 205 // slow, and there is really no value for checking against a max timer. 206 //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime); 207 printf("%s: %1.2fus per call\n", cases[test_case].description, 208 (stop - start).InMillisecondsF() * 1000 / kLoops); 209 test_case++; 210 } 211} 212 213// http://crbug.com/396384 214TEST(TimeTicks, DISABLED_Drift) { 215 // If QPC is disabled, this isn't measuring anything. 216 if (!TimeTicks::IsHighResClockWorking()) 217 return; 218 219 const int kIterations = 100; 220 int64 total_drift = 0; 221 222 for (int i = 0; i < kIterations; ++i) { 223 int64 drift_microseconds = TimeTicks::GetQPCDriftMicroseconds(); 224 225 // Make sure the drift never exceeds our limit. 226 EXPECT_LT(drift_microseconds, 50000); 227 228 // Sleep for a few milliseconds (note that it means 1000 microseconds). 229 // If we check the drift too frequently, it's going to increase 230 // monotonically, making our measurement less realistic. 231 base::PlatformThread::Sleep( 232 base::TimeDelta::FromMilliseconds((i % 2 == 0) ? 1 : 2)); 233 234 total_drift += drift_microseconds; 235 } 236 237 // Sanity check. We expect some time drift to occur, especially across 238 // the number of iterations we do. 239 EXPECT_LT(0, total_drift); 240 241 printf("average time drift in microseconds: %lld\n", 242 total_drift / kIterations); 243} 244 245int64 QPCValueToMicrosecondsSafely(LONGLONG qpc_value, 246 int64 ticks_per_second) { 247 int64 whole_seconds = qpc_value / ticks_per_second; 248 int64 leftover_ticks = qpc_value % ticks_per_second; 249 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + 250 ((leftover_ticks * Time::kMicrosecondsPerSecond) / 251 ticks_per_second); 252 return microseconds; 253} 254 255TEST(TimeTicks, FromQPCValue) { 256 if (!TimeTicks::IsHighResClockWorking()) 257 return; 258 LARGE_INTEGER frequency; 259 QueryPerformanceFrequency(&frequency); 260 int64 ticks_per_second = frequency.QuadPart; 261 LONGLONG qpc_value = Time::kQPCOverflowThreshold; 262 TimeTicks expected_value = TimeTicks::FromInternalValue( 263 QPCValueToMicrosecondsSafely(qpc_value + 1, ticks_per_second)); 264 EXPECT_EQ(expected_value, 265 TimeTicks::FromQPCValue(qpc_value + 1)); 266 expected_value = TimeTicks::FromInternalValue( 267 QPCValueToMicrosecondsSafely(qpc_value, ticks_per_second)); 268 EXPECT_EQ(expected_value, 269 TimeTicks::FromQPCValue(qpc_value)); 270 expected_value = TimeTicks::FromInternalValue( 271 QPCValueToMicrosecondsSafely(qpc_value - 1, ticks_per_second)); 272 EXPECT_EQ(expected_value, 273 TimeTicks::FromQPCValue(qpc_value - 1)); 274}