blob: c403dfd48e2a8736a99c1dc991271de713a3007d [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/metrics/time_ticks_experiment_win.h"
#if defined(OS_WIN)
#include "base/cpu.h"
#include "base/metrics/histogram.h"
#include "base/win/windows_version.h"
#include <windows.h>
namespace chrome {
namespace {
const int kNumIterations = 1000;
} // anonymous namespace
void CollectTimeTicksStats() {
// This bit is supposed to indicate that rdtsc is safe across cores. If so, we
// can use QPC as long as it uses rdtsc.
// TODO(simonjam): We should look for other signals that QPC might be safe and
// test them out here.
base::CPU cpu;
UMA_HISTOGRAM_BOOLEAN("WinTimeTicks.NonStopTsc",
cpu.has_non_stop_time_stamp_counter());
if (!cpu.has_non_stop_time_stamp_counter()) {
return;
}
DWORD_PTR default_mask;
DWORD_PTR system_mask;
if (!GetProcessAffinityMask(GetCurrentProcess(),
&default_mask, &system_mask)) {
return;
}
if (!default_mask) {
return;
}
DWORD_PTR current_mask = 1;
bool failed_to_change_cores = false;
base::win::OSInfo* info = base::win::OSInfo::GetInstance();
UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.VersionTotal", info->version(),
base::win::VERSION_WIN_LAST);
LARGE_INTEGER qpc_frequency;
QueryPerformanceFrequency(&qpc_frequency);
int min_delta = 1e9;
LARGE_INTEGER qpc_last;
QueryPerformanceCounter(&qpc_last);
for (int i = 0; i < kNumIterations; ++i) {
LARGE_INTEGER qpc_now;
QueryPerformanceCounter(&qpc_now);
int delta = static_cast<int>(qpc_now.QuadPart - qpc_last.QuadPart);
if (delta != 0) {
min_delta = std::min(min_delta, delta);
}
qpc_last = qpc_now;
// Change cores every 10 iterations.
if (i % 10 == 0) {
DWORD_PTR old_mask = current_mask;
current_mask <<= 1;
while ((current_mask & default_mask) == 0) {
current_mask <<= 1;
if (!current_mask) {
current_mask = 1;
}
if (current_mask == old_mask) {
break;
}
}
if (!SetThreadAffinityMask(GetCurrentThread(), current_mask)) {
failed_to_change_cores = true;
break;
}
}
}
SetThreadAffinityMask(GetCurrentThread(), default_mask);
if (failed_to_change_cores) {
UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.FailedToChangeCores",
info->version(), base::win::VERSION_WIN_LAST);
return;
}
if (min_delta < 0) {
UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.TickedBackwards", info->version(),
base::win::VERSION_WIN_LAST);
return;
}
int min_delta_ns = static_cast<int>(
min_delta * (1e9 / qpc_frequency.QuadPart));
UMA_HISTOGRAM_CUSTOM_COUNTS("WinTimeTicks.MinResolutionNanoseconds",
min_delta_ns, 1, 1000000, 50);
bool success = min_delta_ns <= 10000;
if (success) {
UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.VersionSuccessful",
info->version(), base::win::VERSION_WIN_LAST);
}
}
} // namespace chrome
#endif // defined(OS_WIN)