summaryrefslogtreecommitdiffstats
path: root/chrome/browser/metrics/time_ticks_experiment_win.cc
blob: c403dfd48e2a8736a99c1dc991271de713a3007d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 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 {

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;
  }

  DWORD_PTR default_mask;
  DWORD_PTR system_mask;
  if (!GetProcessAffinityMask(GetCurrentProcess(),
                              &default_mask, &system_mask)) {
    return;
  }
  if (!default_mask) {
    return;
  }

  DWORD_PTR current_mask = 1;
  bool failed_to_change_cores = false;

  base::win::OSInfo* info = base::win::OSInfo::GetInstance();
  UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.VersionTotal", info->version(),
                            base::win::VERSION_WIN_LAST);

  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;

    // Change cores every 10 iterations.
    if (i % 10 == 0) {
      DWORD_PTR old_mask = current_mask;
      current_mask <<= 1;
      while ((current_mask & default_mask) == 0) {
        current_mask <<= 1;
        if (!current_mask) {
          current_mask = 1;
        }
        if (current_mask == old_mask) {
          break;
        }
      }
      if (!SetThreadAffinityMask(GetCurrentThread(), current_mask)) {
        failed_to_change_cores = true;
        break;
      }
    }
  }

  SetThreadAffinityMask(GetCurrentThread(), default_mask);
  if (failed_to_change_cores) {
    UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.FailedToChangeCores",
                              info->version(), base::win::VERSION_WIN_LAST);
    return;
  }

  if (min_delta < 0) {
    UMA_HISTOGRAM_ENUMERATION("WinTimeTicks.TickedBackwards", info->version(),
                              base::win::VERSION_WIN_LAST);
    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

#endif  // defined(OS_WIN)