• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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 <stdint.h>
8 
9 #include <algorithm>
10 #include <cstdio>
11 
12 #include "base/bit_cast.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/time/time.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/perf/perf_result_reporter.h"
17 #include "third_party/google_benchmark/src/include/benchmark/benchmark.h"
18 
19 namespace base {
20 namespace {
21 
22 constexpr char kCountDelta[] = ".count_time_imprecise_precise";
23 constexpr char kAvgDelta[] = ".avg_time_precise_imprecise";
24 constexpr char kMinDelta[] = ".min_time_precise_imprecise";
25 constexpr char kMaxDelta[] = ".max_time_precise_imprecise";
26 
27 // Copied from base/time_win.cc.
28 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
29 // 100-nanosecond intervals since January 1, 1601 (UTC)."
FileTimeToMicroseconds(const FILETIME & ft)30 int64_t FileTimeToMicroseconds(const FILETIME& ft) {
31   // Need to bit_cast to fix alignment, then divide by 10 to convert
32   // 100-nanoseconds to microseconds. This only works on little-endian
33   // machines.
34   return bit_cast<int64_t, FILETIME>(ft) / 10;
35 }
36 
CurrentTimePrecise()37 int64_t CurrentTimePrecise() {
38   FILETIME ft;
39   ::GetSystemTimePreciseAsFileTime(&ft);
40   return FileTimeToMicroseconds(ft);
41 }
42 
CurrentTimeImprecise()43 int64_t CurrentTimeImprecise() {
44   FILETIME ft;
45   ::GetSystemTimeAsFileTime(&ft);
46   return FileTimeToMicroseconds(ft);
47 }
48 
49 }  // namespace
50 
51 // This test case compares the performances of CurrentWallclockMicroseconds()
52 // implemented with using GetSystemTimeAsFileTime() or
53 // GetSystemTimePreciseAsFileTime().
TEST(WinTimePerfTest,Precise)54 TEST(WinTimePerfTest, Precise) {
55   // The time interval that likely grabs a hardware timer interruption.
56   static constexpr TimeDelta kInterval = Milliseconds(50);
57   // The loop amount of calling the wall clock, it guaranties non zero amount of
58   // time ticks.
59   static constexpr int kLoop = 1000;
60 
61   int precise_counter = 0;
62   TimeDelta precise_max_time;
63   TimeDelta precise_min_time = TimeDelta::Max();
64 
65   TimeTicks begin = TimeTicks::Now();
66   TimeTicks end = begin + kInterval;
67   for (TimeTicks start = begin; start < end; start = TimeTicks::Now()) {
68     for (int i = 0; i < kLoop; ++i) {
69       int64_t current = CurrentTimePrecise();
70       ::benchmark::DoNotOptimize(current);
71     }
72 
73     const TimeDelta delta = TimeTicks::Now() - start;
74     precise_min_time = std::min(precise_min_time, delta);
75     precise_max_time = std::max(precise_max_time, delta);
76     precise_counter += kLoop;
77   }
78   const TimeDelta precise_duration = TimeTicks::Now() - begin;
79 
80   int imprecise_counter = 0;
81   TimeDelta imprecise_max_time;
82   TimeDelta imprecise_min_time = TimeDelta::Max();
83 
84   begin = TimeTicks::Now();
85   end = begin + kInterval;
86   for (TimeTicks start = begin; start < end; start = TimeTicks::Now()) {
87     for (int i = 0; i < kLoop; ++i) {
88       int64_t current = CurrentTimeImprecise();
89       ::benchmark::DoNotOptimize(current);
90     }
91 
92     const TimeDelta delta = TimeTicks::Now() - start;
93     imprecise_min_time = std::min(imprecise_min_time, delta);
94     imprecise_max_time = std::max(imprecise_max_time, delta);
95     imprecise_counter += kLoop;
96   }
97   const TimeDelta imprecise_duration = TimeTicks::Now() - begin;
98 
99   ASSERT_GT(precise_counter, 0);
100   ASSERT_GT(imprecise_counter, 0);
101 
102   // Format output like in Google Benchmark.
103   std::printf("----------------------------------------------------------\n");
104   std::printf("             Min Time    Avg Time    Max Time   Iterations\n");
105   std::printf("----------------------------------------------------------\n");
106   std::printf("Precise   %8lld ns %8lld ns %8lld ns %12d\n",
107               precise_min_time.InNanoseconds() / kLoop,
108               precise_duration.InNanoseconds() / precise_counter,
109               precise_max_time.InNanoseconds() / kLoop, precise_counter);
110   std::printf("Imprecise %8lld ns %8lld ns %8lld ns %12d\n",
111               imprecise_min_time.InNanoseconds() / kLoop,
112               imprecise_duration.InNanoseconds() / imprecise_counter,
113               imprecise_max_time.InNanoseconds() / kLoop, imprecise_counter);
114 
115   // Negative values mean the function ::GetSystemTimePreciseAsFileTime() wins.
116 
117   // Count of calls in kInterval (50) ms.
118   const double count_delta = imprecise_counter - precise_counter;
119   const double avg_delta = kInterval.InNanoseconds() / precise_counter -
120                            kInterval.InNanoseconds() / imprecise_counter;
121   const double min_delta =
122       (precise_min_time.InNanoseconds() - imprecise_min_time.InNanoseconds()) /
123       kLoop;
124   const double max_delta =
125       (precise_max_time.InNanoseconds() - imprecise_max_time.InNanoseconds()) /
126       kLoop;
127 
128   perf_test::PerfResultReporter reporter("WinTime", "delta");
129   reporter.RegisterFyiMetric(
130       kCountDelta, StringPrintf("/%lldms", kInterval.InMilliseconds()));
131   reporter.RegisterFyiMetric(kAvgDelta, "ns");
132   reporter.RegisterFyiMetric(kMinDelta, "ns");
133   reporter.RegisterFyiMetric(kMaxDelta, "ns");
134 
135   reporter.AddResult(kCountDelta, count_delta);
136   reporter.AddResult(kAvgDelta, avg_delta);
137   reporter.AddResult(kMinDelta, min_delta);
138   reporter.AddResult(kMaxDelta, max_delta);
139 }
140 
141 }  // namespace base
142