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