• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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