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