#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";
int64_t FileTimeToMicroseconds(const FILETIME& ft) {
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);
}
}
TEST(WinTimePerfTest, Precise) {
static constexpr TimeDelta kInterval = Milliseconds(50);
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);
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);
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);
}
}