Chromium Code Reviews| Index: chrome/browser/metrics/time_ticks_experiment_win.cc |
| diff --git a/chrome/browser/metrics/time_ticks_experiment_win.cc b/chrome/browser/metrics/time_ticks_experiment_win.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..67aaf16bcfd5a61deca6cea9fb6c90f2a032361d |
| --- /dev/null |
| +++ b/chrome/browser/metrics/time_ticks_experiment_win.cc |
| @@ -0,0 +1,126 @@ |
| +// 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_browser_metrics { |
| + |
| +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; |
| + } |
| + |
| + SYSTEM_INFO sys_info; |
| + GetSystemInfo(&sys_info); |
| + DWORD num_cores = sys_info.dwNumberOfProcessors; |
| + DWORD current_core = 0; |
| + |
| + typedef DWORD (WINAPI *GetCurrentProcessorFunction)(); |
| + GetCurrentProcessorFunction get_current_processor_func = NULL; |
| + |
| + if (num_cores > 1) { |
| + // Windows XP doesn't have a function to tell which core we're currently |
| + // running on. Here, we determine if the function is available and use it if |
| + // so. If the function is not available, we bail. |
| + HMODULE module = GetModuleHandle(TEXT("kernel32.dll")); |
| + if (!module) { |
| + return; |
| + } |
| + get_current_processor_func = |
| + reinterpret_cast<GetCurrentProcessorFunction>( |
| + GetProcAddress(module, "GetCurrentProcessorNumber")); |
| + if (!get_current_processor_func) { |
|
Sigurður Ásgeirsson
2013/04/17 13:36:16
since this function is unavailable on Windows XP,
|
| + return; |
| + } |
| + current_core = get_current_processor_func(); |
| + } |
| + |
| + base::win::OSInfo* info = base::win::OSInfo::GetInstance(); |
| + UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.VersionTotal", info->version(), |
| + base::win::VERSION_WIN_LAST); |
| + |
| + DWORD starting_core = get_current_processor_func(); |
| + bool did_change_cores = false; |
| + |
| + 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; |
| + |
| + if (num_cores > 1 && (i % 100) == 0) { |
| + ++current_core; |
| + if (current_core > num_cores) { |
| + current_core = 0; |
| + } |
| + SetThreadAffinityMask(GetCurrentThread(), 1 << current_core); |
|
Sigurður Ásgeirsson
2013/04/17 13:36:16
This function can fail and a failure in this funct
|
| + if (!did_change_cores && |
|
Sigurður Ásgeirsson
2013/04/17 13:36:16
My earlier comment on this code was to the effect
|
| + get_current_processor_func() != starting_core) { |
| + did_change_cores = true; |
| + } |
| + } |
| + } |
| + |
| + if (num_cores > 1) { |
| + if (did_change_cores) { |
| + UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.ChangedCores", info->version(), |
| + base::win::VERSION_WIN_LAST); |
| + } else { |
| + UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.FailedToChangeCores", |
| + info->version(), base::win::VERSION_WIN_LAST); |
| + } |
| + } |
| + |
| + if (min_delta >= 0) { |
| + UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.NonDecreasing", info->version(), |
| + base::win::VERSION_WIN_LAST); |
| + } else { |
| + 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_browser_net |
| + |
| +#endif // defined(OS_WIN) |