• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CollectTimeTicksStats()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