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