Home | History | Annotate | Download | only in metrics
      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