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 142
|
// 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 "base/time/time.h"
#include <windows.h>
#include <stdint.h>
#include <algorithm>
#include <cstdio>
#include "base/bit_cast.h"
#include "base/strings/stringprintf.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
|