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) |