1 // Copyright 2012 The Chromium Authors
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 "base/time/time.h"
6
7 #include <windows.h>
8
9 #include <mmsystem.h>
10 #include <process.h>
11 #include <stdint.h>
12 #include <windows.foundation.h>
13
14 #include <algorithm>
15 #include <cmath>
16 #include <limits>
17 #include <vector>
18
19 #include "base/strings/string_piece.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/win/registry.h"
22 #include "build/build_config.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace base {
26 namespace {
27
28 // For TimeDelta::ConstexprInitialization
29 constexpr int kExpectedDeltaInMilliseconds = 10;
30 constexpr TimeDelta kConstexprTimeDelta =
31 Milliseconds(kExpectedDeltaInMilliseconds);
32
33 class MockTimeTicks : public TimeTicks {
34 public:
Ticker()35 static DWORD Ticker() {
36 return static_cast<int>(InterlockedIncrement(&ticker_));
37 }
38
InstallTicker()39 static void InstallTicker() {
40 old_tick_function_ = SetMockTickFunction(&Ticker);
41 ticker_ = -5;
42 }
43
UninstallTicker()44 static void UninstallTicker() { SetMockTickFunction(old_tick_function_); }
45
46 private:
47 static volatile LONG ticker_;
48 static TickFunctionType old_tick_function_;
49 };
50
51 volatile LONG MockTimeTicks::ticker_;
52 MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_;
53
54 HANDLE g_rollover_test_start;
55
RolloverTestThreadMain(void * param)56 unsigned __stdcall RolloverTestThreadMain(void* param) {
57 int64_t counter = reinterpret_cast<int64_t>(param);
58 DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE);
59 EXPECT_EQ(rv, WAIT_OBJECT_0);
60
61 TimeTicks last = TimeTicks::Now();
62 for (int index = 0; index < counter; index++) {
63 TimeTicks now = TimeTicks::Now();
64 int64_t milliseconds = (now - last).InMilliseconds();
65 // This is a tight loop; we could have looped faster than our
66 // measurements, so the time might be 0 millis.
67 EXPECT_GE(milliseconds, 0);
68 EXPECT_LT(milliseconds, 250);
69 last = now;
70 }
71 return 0;
72 }
73
74 #if defined(_M_ARM64) && defined(__clang__)
75 #define ReadCycleCounter() _ReadStatusReg(ARM64_PMCCNTR_EL0)
76 #else
77 #define ReadCycleCounter() __rdtsc()
78 #endif
79
80 // Measure the performance of the CPU cycle counter so that we can compare it to
81 // the overhead of QueryPerformanceCounter. A hard-coded frequency is used
82 // because we don't care about the accuracy of the results, we just need to do
83 // the work. The amount of work is not exactly the same as in TimeTicks::Now
84 // (some steps are skipped) but that doesn't seem to materially affect the
85 // results.
GetTSC()86 TimeTicks GetTSC() {
87 // Using a fake cycle counter frequency for test purposes.
88 return TimeTicks() + Microseconds(ReadCycleCounter() *
89 Time::kMicrosecondsPerSecond / 10000000);
90 }
91
92 } // namespace
93
94 // This test spawns many threads, and can occasionally fail due to resource
95 // exhaustion in the presence of ASan.
96 #if defined(ADDRESS_SANITIZER)
97 #define MAYBE_WinRollover DISABLED_WinRollover
98 #else
99 #define MAYBE_WinRollover WinRollover
100 #endif
TEST(TimeTicks,MAYBE_WinRollover)101 TEST(TimeTicks, MAYBE_WinRollover) {
102 // The internal counter rolls over at ~49days. We'll use a mock
103 // timer to test this case.
104 // Basic test algorithm:
105 // 1) Set clock to rollover - N
106 // 2) Create N threads
107 // 3) Start the threads
108 // 4) Each thread loops through TimeTicks() N times
109 // 5) Each thread verifies integrity of result.
110
111 const int kThreads = 8;
112 // Use int64_t so we can cast into a void* without a compiler warning.
113 const int64_t kChecks = 10;
114
115 // It takes a lot of iterations to reproduce the bug!
116 // (See bug 1081395)
117 for (int loop = 0; loop < 4096; loop++) {
118 // Setup
119 MockTimeTicks::InstallTicker();
120 g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0);
121 HANDLE threads[kThreads];
122
123 for (int index = 0; index < kThreads; index++) {
124 void* argument = reinterpret_cast<void*>(kChecks);
125 unsigned thread_id;
126 threads[index] = reinterpret_cast<HANDLE>(_beginthreadex(
127 NULL, 0, RolloverTestThreadMain, argument, 0, &thread_id));
128 EXPECT_NE((HANDLE)NULL, threads[index]);
129 }
130
131 // Start!
132 SetEvent(g_rollover_test_start);
133
134 // Wait for threads to finish
135 for (int index = 0; index < kThreads; index++) {
136 DWORD rv = WaitForSingleObject(threads[index], INFINITE);
137 EXPECT_EQ(rv, WAIT_OBJECT_0);
138 // Since using _beginthreadex() (as opposed to _beginthread),
139 // an explicit CloseHandle() is supposed to be called.
140 CloseHandle(threads[index]);
141 }
142
143 CloseHandle(g_rollover_test_start);
144
145 // Teardown
146 MockTimeTicks::UninstallTicker();
147 }
148 }
149
TEST(TimeTicks,SubMillisecondTimers)150 TEST(TimeTicks, SubMillisecondTimers) {
151 // IsHighResolution() is false on some systems. Since the product still works
152 // even if it's false, it makes this entire test questionable.
153 if (!TimeTicks::IsHighResolution())
154 return;
155
156 // Run kRetries attempts to see a sub-millisecond timer.
157 constexpr int kRetries = 1000;
158 for (int index = 0; index < kRetries; index++) {
159 const TimeTicks start_time = TimeTicks::Now();
160 TimeDelta delta;
161 // Spin until the clock has detected a change.
162 do {
163 delta = TimeTicks::Now() - start_time;
164 } while (delta.is_zero());
165 if (!delta.InMilliseconds())
166 return;
167 }
168 ADD_FAILURE() << "Never saw a sub-millisecond timer.";
169 }
170
TEST(TimeTicks,TimeGetTimeCaps)171 TEST(TimeTicks, TimeGetTimeCaps) {
172 // Test some basic assumptions that we expect about how timeGetDevCaps works.
173
174 TIMECAPS caps;
175 MMRESULT status = timeGetDevCaps(&caps, sizeof(caps));
176 ASSERT_EQ(static_cast<MMRESULT>(MMSYSERR_NOERROR), status);
177
178 EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
179 EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
180 EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
181 EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
182 printf("timeGetTime range is %d to %dms\n", caps.wPeriodMin, caps.wPeriodMax);
183 }
184
TEST(TimeTicks,QueryPerformanceFrequency)185 TEST(TimeTicks, QueryPerformanceFrequency) {
186 // Test some basic assumptions that we expect about QPC.
187
188 LARGE_INTEGER frequency;
189 BOOL rv = QueryPerformanceFrequency(&frequency);
190 EXPECT_EQ(TRUE, rv);
191 EXPECT_GT(frequency.QuadPart, 1000000); // Expect at least 1MHz
192 printf("QueryPerformanceFrequency is %5.2fMHz\n",
193 frequency.QuadPart / 1000000.0);
194 }
195
TEST(TimeTicks,TimerPerformance)196 TEST(TimeTicks, TimerPerformance) {
197 // Verify that various timer mechanisms can always complete quickly.
198 // Note: This is a somewhat arbitrary test.
199 const int kLoops = 500000;
200
201 typedef TimeTicks (*TestFunc)();
202 struct TestCase {
203 TestFunc func;
204 const char* description;
205 };
206 // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time)
207 // in order to create a single test case list.
208 static_assert(sizeof(TimeTicks) == sizeof(Time),
209 "TimeTicks and Time must be the same size");
210 std::vector<TestCase> cases;
211 cases.push_back({reinterpret_cast<TestFunc>(&Time::Now), "Time::Now"});
212 cases.push_back({&TimeTicks::Now, "TimeTicks::Now"});
213 cases.push_back({&GetTSC, "CPUCycleCounter"});
214
215 if (ThreadTicks::IsSupported()) {
216 ThreadTicks::WaitUntilInitialized();
217 cases.push_back(
218 {reinterpret_cast<TestFunc>(&ThreadTicks::Now), "ThreadTicks::Now"});
219 }
220
221 // Warm up the CPU to its full clock rate so that we get accurate timing
222 // information.
223 DWORD start_tick = GetTickCount();
224 const DWORD kWarmupMs = 50;
225 for (;;) {
226 DWORD elapsed = GetTickCount() - start_tick;
227 if (elapsed > kWarmupMs)
228 break;
229 }
230
231 for (const auto& test_case : cases) {
232 TimeTicks start = TimeTicks::Now();
233 for (int index = 0; index < kLoops; index++)
234 test_case.func();
235 TimeTicks stop = TimeTicks::Now();
236 // Turning off the check for acceptible delays. Without this check,
237 // the test really doesn't do much other than measure. But the
238 // measurements are still useful for testing timers on various platforms.
239 // The reason to remove the check is because the tests run on many
240 // buildbots, some of which are VMs. These machines can run horribly
241 // slow, and there is really no value for checking against a max timer.
242 // const int kMaxTime = 35; // Maximum acceptible milliseconds for test.
243 // EXPECT_LT((stop - start).InMilliseconds(), kMaxTime);
244 printf("%s: %1.2fus per call\n", test_case.description,
245 (stop - start).InMillisecondsF() * 1000 / kLoops);
246 }
247 }
248
249 #if !defined(ARCH_CPU_ARM64)
250 // This test is disabled on Windows ARM64 systems because TSCTicksPerSecond is
251 // only used in Chromium for QueryThreadCycleTime, and QueryThreadCycleTime
252 // doesn't use a constant-rate timer on ARM64.
TEST(TimeTicks,TSCTicksPerSecond)253 TEST(TimeTicks, TSCTicksPerSecond) {
254 if (time_internal::HasConstantRateTSC()) {
255 ThreadTicks::WaitUntilInitialized();
256
257 // Read the CPU frequency from the registry.
258 base::win::RegKey processor_key(
259 HKEY_LOCAL_MACHINE,
260 L"Hardware\\Description\\System\\CentralProcessor\\0", KEY_QUERY_VALUE);
261 ASSERT_TRUE(processor_key.Valid());
262 DWORD processor_mhz_from_registry;
263 ASSERT_EQ(ERROR_SUCCESS,
264 processor_key.ReadValueDW(L"~MHz", &processor_mhz_from_registry));
265
266 // Expect the measured TSC frequency to be similar to the processor
267 // frequency from the registry (0.5% error).
268 double tsc_mhz_measured = time_internal::TSCTicksPerSecond() / 1e6;
269 EXPECT_NEAR(tsc_mhz_measured, processor_mhz_from_registry,
270 0.005 * processor_mhz_from_registry);
271 }
272 }
273 #endif
274
TEST(TimeTicks,FromQPCValue)275 TEST(TimeTicks, FromQPCValue) {
276 if (!TimeTicks::IsHighResolution())
277 return;
278
279 LARGE_INTEGER frequency;
280 ASSERT_TRUE(QueryPerformanceFrequency(&frequency));
281 const int64_t ticks_per_second = frequency.QuadPart;
282 ASSERT_GT(ticks_per_second, 0);
283
284 // Generate the tick values to convert, advancing the tick count by varying
285 // amounts. These values will ensure that both the fast and overflow-safe
286 // conversion logic in FromQPCValue() is tested, and across the entire range
287 // of possible QPC tick values.
288 std::vector<int64_t> test_cases;
289 test_cases.push_back(0);
290
291 // Build the test cases.
292 {
293 const int kNumAdvancements = 100;
294 int64_t ticks = 0;
295 int64_t ticks_increment = 10;
296 for (int i = 0; i < kNumAdvancements; ++i) {
297 test_cases.push_back(ticks);
298 ticks += ticks_increment;
299 ticks_increment = ticks_increment * 6 / 5;
300 }
301 test_cases.push_back(Time::kQPCOverflowThreshold - 1);
302 test_cases.push_back(Time::kQPCOverflowThreshold);
303 test_cases.push_back(Time::kQPCOverflowThreshold + 1);
304 ticks = Time::kQPCOverflowThreshold + 10;
305 ticks_increment = 10;
306 for (int i = 0; i < kNumAdvancements; ++i) {
307 test_cases.push_back(ticks);
308 ticks += ticks_increment;
309 ticks_increment = ticks_increment * 6 / 5;
310 }
311 test_cases.push_back(std::numeric_limits<int64_t>::max());
312 }
313
314 // Test that the conversions using FromQPCValue() match those computed here
315 // using simple floating-point arithmetic. The floating-point math provides
316 // enough precision for all reasonable values to confirm that the
317 // implementation is correct to the microsecond, and for "very large" values
318 // it confirms that the answer is very close to correct.
319 for (int64_t ticks : test_cases) {
320 const double expected_microseconds_since_origin =
321 (static_cast<double>(ticks) * Time::kMicrosecondsPerSecond) /
322 ticks_per_second;
323 const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks);
324 const double converted_microseconds_since_origin =
325 (converted_value - TimeTicks()).InMicrosecondsF();
326 // When we test with very large numbers we end up in a range where adjacent
327 // double values are far apart - 512.0 apart in one test failure. In that
328 // situation it makes no sense for our epsilon to be 1.0 - it should be
329 // the difference between adjacent doubles.
330 double epsilon = nextafter(expected_microseconds_since_origin, INFINITY) -
331 expected_microseconds_since_origin;
332 // Epsilon must be at least 1.0 because converted_microseconds_since_origin
333 // comes from an integral value, and expected_microseconds_since_origin is
334 // a double that is expected to be up to 0.999 larger. In addition, due to
335 // multiple roundings in the double calculation the actual error can be
336 // slightly larger than 1.0, even when the converted value is perfect. This
337 // epsilon value was chosen because it is slightly larger than the error
338 // seen in a test failure caused by the double rounding.
339 epsilon = std::max(epsilon, 1.002);
340 EXPECT_NEAR(expected_microseconds_since_origin,
341 converted_microseconds_since_origin, epsilon)
342 << "ticks=" << ticks << ", to be converted via logic path: "
343 << (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE");
344 }
345 }
346
TEST(TimeDelta,ConstexprInitialization)347 TEST(TimeDelta, ConstexprInitialization) {
348 // Make sure that TimeDelta works around crbug.com/635974
349 EXPECT_EQ(kExpectedDeltaInMilliseconds, kConstexprTimeDelta.InMilliseconds());
350 }
351
TEST(TimeDelta,FromFileTime)352 TEST(TimeDelta, FromFileTime) {
353 FILETIME ft;
354 ft.dwLowDateTime = 1001;
355 ft.dwHighDateTime = 0;
356
357 // 100100 ns ~= 100 us.
358 EXPECT_EQ(Microseconds(100), TimeDelta::FromFileTime(ft));
359
360 ft.dwLowDateTime = 0;
361 ft.dwHighDateTime = 1;
362
363 // 2^32 * 100 ns ~= 2^32 * 10 us.
364 EXPECT_EQ(Microseconds((1ull << 32) / 10), TimeDelta::FromFileTime(ft));
365 }
366
TEST(TimeDelta,FromWinrtDateTime)367 TEST(TimeDelta, FromWinrtDateTime) {
368 ABI::Windows::Foundation::DateTime dt;
369 dt.UniversalTime = 0;
370
371 // 0 UniversalTime = no delta since epoch.
372 EXPECT_EQ(TimeDelta(), TimeDelta::FromWinrtDateTime(dt));
373
374 dt.UniversalTime = 101;
375
376 // 101 * 100 ns ~= 10.1 microseconds.
377 EXPECT_EQ(Microseconds(10.1), TimeDelta::FromWinrtDateTime(dt));
378 }
379
TEST(TimeDelta,ToWinrtDateTime)380 TEST(TimeDelta, ToWinrtDateTime) {
381 auto time_delta = Seconds(0);
382
383 // No delta since epoch = 0 DateTime.
384 EXPECT_EQ(0, time_delta.ToWinrtDateTime().UniversalTime);
385
386 time_delta = Microseconds(10);
387
388 // 10 microseconds = 100 * 100 ns.
389 EXPECT_EQ(100, time_delta.ToWinrtDateTime().UniversalTime);
390 }
391
TEST(TimeDelta,FromWinrtTimeSpan)392 TEST(TimeDelta, FromWinrtTimeSpan) {
393 ABI::Windows::Foundation::TimeSpan ts;
394 ts.Duration = 0;
395
396 // 0.
397 EXPECT_EQ(TimeDelta(), TimeDelta::FromWinrtTimeSpan(ts));
398
399 ts.Duration = 101;
400
401 // 101 * 100 ns ~= 10.1 microseconds.
402 EXPECT_EQ(Microseconds(10.1), TimeDelta::FromWinrtTimeSpan(ts));
403 }
404
TEST(TimeDelta,ToWinrtTimeSpan)405 TEST(TimeDelta, ToWinrtTimeSpan) {
406 auto time_delta = Seconds(0);
407
408 // 0.
409 EXPECT_EQ(0, time_delta.ToWinrtTimeSpan().Duration);
410
411 time_delta = Microseconds(10);
412
413 // 10 microseconds = 100 * 100 ns.
414 EXPECT_EQ(100, time_delta.ToWinrtTimeSpan().Duration);
415 }
416
TEST(HighResolutionTimer,GetUsage)417 TEST(HighResolutionTimer, GetUsage) {
418 Time::ResetHighResolutionTimerUsage();
419
420 // 0% usage since the timer isn't activated regardless of how much time has
421 // elapsed.
422 EXPECT_EQ(0.0, Time::GetHighResolutionTimerUsage());
423 Sleep(10);
424 EXPECT_EQ(0.0, Time::GetHighResolutionTimerUsage());
425
426 Time::ActivateHighResolutionTimer(true);
427 Time::ResetHighResolutionTimerUsage();
428
429 Sleep(20);
430 // 100% usage since the timer has been activated entire time.
431 EXPECT_EQ(100.0, Time::GetHighResolutionTimerUsage());
432
433 Time::ActivateHighResolutionTimer(false);
434 Sleep(20);
435 double usage1 = Time::GetHighResolutionTimerUsage();
436 // usage1 should be about 50%.
437 EXPECT_LT(usage1, 100.0);
438 EXPECT_GT(usage1, 0.0);
439
440 Time::ActivateHighResolutionTimer(true);
441 Sleep(10);
442 Time::ActivateHighResolutionTimer(false);
443 double usage2 = Time::GetHighResolutionTimerUsage();
444 // usage2 should be about 60%.
445 EXPECT_LT(usage2, 100.0);
446 EXPECT_GT(usage2, usage1);
447
448 Time::ResetHighResolutionTimerUsage();
449 EXPECT_EQ(0.0, Time::GetHighResolutionTimerUsage());
450 }
451
452 } // namespace base
453