1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/metrics/time_ticks_experiment_win.h" 6 7 #if defined(OS_WIN) 8 9 #include "base/cpu.h" 10 #include "base/metrics/histogram.h" 11 #include "base/win/windows_version.h" 12 13 #include <windows.h> 14 15 namespace chrome { 16 17 namespace { 18 19 const int kNumIterations = 1000; 20 21 } // anonymous namespace 22 23 void CollectTimeTicksStats() { 24 // This bit is supposed to indicate that rdtsc is safe across cores. If so, we 25 // can use QPC as long as it uses rdtsc. 26 // TODO(simonjam): We should look for other signals that QPC might be safe and 27 // test them out here. 28 base::CPU cpu; 29 UMA_HISTOGRAM_BOOLEAN("WinTimeTicks.NonStopTsc", 30 cpu.has_non_stop_time_stamp_counter()); 31 if (!cpu.has_non_stop_time_stamp_counter()) { 32 return; 33 } 34 35 DWORD_PTR default_mask; 36 DWORD_PTR system_mask; 37 if (!GetProcessAffinityMask(GetCurrentProcess(), 38 &default_mask, &system_mask)) { 39 return; 40 } 41 if (!default_mask) { 42 return; 43 } 44 45 DWORD_PTR current_mask = 1; 46 bool failed_to_change_cores = false; 47 48 base::win::OSInfo* info = base::win::OSInfo::GetInstance(); 49 UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.VersionTotal", info->version(), 50 base::win::VERSION_WIN_LAST); 51 52 LARGE_INTEGER qpc_frequency; 53 QueryPerformanceFrequency(&qpc_frequency); 54 55 int min_delta = 1e9; 56 LARGE_INTEGER qpc_last; 57 QueryPerformanceCounter(&qpc_last); 58 for (int i = 0; i < kNumIterations; ++i) { 59 LARGE_INTEGER qpc_now; 60 QueryPerformanceCounter(&qpc_now); 61 int delta = static_cast<int>(qpc_now.QuadPart - qpc_last.QuadPart); 62 if (delta != 0) { 63 min_delta = std::min(min_delta, delta); 64 } 65 qpc_last = qpc_now; 66 67 // Change cores every 10 iterations. 68 if (i % 10 == 0) { 69 DWORD_PTR old_mask = current_mask; 70 current_mask <<= 1; 71 while ((current_mask & default_mask) == 0) { 72 current_mask <<= 1; 73 if (!current_mask) { 74 current_mask = 1; 75 } 76 if (current_mask == old_mask) { 77 break; 78 } 79 } 80 if (!SetThreadAffinityMask(GetCurrentThread(), current_mask)) { 81 failed_to_change_cores = true; 82 break; 83 } 84 } 85 } 86 87 SetThreadAffinityMask(GetCurrentThread(), default_mask); 88 if (failed_to_change_cores) { 89 UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.FailedToChangeCores", 90 info->version(), base::win::VERSION_WIN_LAST); 91 return; 92 } 93 94 if (min_delta < 0) { 95 UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.TickedBackwards", info->version(), 96 base::win::VERSION_WIN_LAST); 97 return; 98 } 99 100 int min_delta_ns = static_cast<int>( 101 min_delta * (1e9 / qpc_frequency.QuadPart)); 102 UMA_HISTOGRAM_CUSTOM_COUNTS("WinTimeTicks.MinResolutionNanoseconds", 103 min_delta_ns, 1, 1000000, 50); 104 105 bool success = min_delta_ns <= 10000; 106 if (success) { 107 UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.VersionSuccessful", 108 info->version(), base::win::VERSION_WIN_LAST); 109 } 110 } 111 112 } // namespace chrome 113 114 #endif // defined(OS_WIN) 115