YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/gutil/cycleclock-inl.h
Line
Count
Source
1
// Copyright (C) 1999-2007 Google, Inc.
2
//
3
// The following only applies to changes made to this file as part of YugaByte development.
4
//
5
// Portions Copyright (c) YugaByte, Inc.
6
//
7
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8
// in compliance with the License.  You may obtain a copy of the License at
9
//
10
// http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software distributed under the License
13
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14
// or implied.  See the License for the specific language governing permissions and limitations
15
// under the License.
16
//
17
// Licensed to the Apache Software Foundation (ASF) under one
18
// or more contributor license agreements.  See the NOTICE file
19
// distributed with this work for additional information
20
// regarding copyright ownership.  The ASF licenses this file
21
// to you under the Apache License, Version 2.0 (the
22
// "License"); you may not use this file except in compliance
23
// with the License.  You may obtain a copy of the License at
24
//
25
//   http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing,
28
// software distributed under the License is distributed on an
29
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
30
// KIND, either express or implied.  See the License for the
31
// specific language governing permissions and limitations
32
// under the License.
33
//
34
// All rights reserved.
35
// Extracted from base/timer.h by jrvb
36
37
// The implementation of CycleClock::Now()
38
// See cycleclock.h
39
//
40
// IWYU pragma: private, include "base/cycleclock.h"
41
42
// NOTE: only i386 and x86_64 have been well tested.
43
// PPC, sparc, alpha, and ia64 are based on
44
//    http://peter.kuscsik.com/wordpress/?p=14
45
// with modifications by m3b.  See also
46
//    https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h
47
48
#ifndef GUTIL_CYCLECLOCK_INL_H_
49
#define GUTIL_CYCLECLOCK_INL_H_
50
51
#include <sys/time.h>
52
53
#include "yb/gutil/port.h"
54
#include "yb/gutil/arm_instruction_set_select.h"
55
56
// Please do not nest #if directives.  Keep one section, and one #if per
57
// platform.
58
59
// For historical reasons, the frequency on some platforms is scaled to be
60
// close to the platform's core clock frequency.  This is not guaranteed by the
61
// interface, and may change in future implementations.
62
63
// ----------------------------------------------------------------
64
#if defined(__APPLE__)
65
#include <mach/mach_time.h>
66
86.5M
inline int64 CycleClock::Now() {
67
  // this goes at the top because we need ALL Macs, regardless of
68
  // architecture, to return the number of "mach time units" that
69
  // have passed since startup.  See sysinfo.cc where
70
  // InitializeSystemInfo() sets the supposed cpu clock frequency of
71
  // macs to the number of mach time units per second, not actual
72
  // CPU clock frequency (which can change in the face of CPU
73
  // frequency scaling).  Also note that when the Mac sleeps, this
74
  // counter pauses; it does not continue counting, nor does it
75
  // reset to zero.
76
86.5M
  return mach_absolute_time();
77
86.5M
}
78
79
// ----------------------------------------------------------------
80
#elif defined(__i386__)
81
inline int64 CycleClock::Now() {
82
  int64 ret;
83
  __asm__ volatile("rdtsc" : "=A" (ret));
84
  return ret;
85
}
86
87
// ----------------------------------------------------------------
88
#elif defined(__x86_64__) || defined(__amd64__)
89
inline int64 CycleClock::Now() {
90
  uint64 low, high;
91
  __asm__ volatile("rdtsc" : "=a" (low), "=d" (high));
92
  return (high << 32) | low;
93
}
94
95
// ----------------------------------------------------------------
96
#elif defined(__powerpc__) || defined(__ppc__)
97
#define SPR_TB 268
98
#define SPR_TBU 269
99
inline int64 CycleClock::Now() {
100
  uint64 time_base_value;
101
  if (sizeof(void*) == 8) {
102
    // On PowerPC64, time base can be read with one SPR read.
103
    asm volatile("mfspr %0, %1" : "=r" (time_base_value) : "i"(SPR_TB));
104
  } else {
105
    uint32 tbl, tbu0, tbu1;
106
    asm volatile (" mfspr %0, %3\n"
107
                  " mfspr %1, %4\n"
108
                  " mfspr %2, %3\n" :
109
                  "=r"(tbu0), "=r"(tbl), "=r"(tbu1) :
110
                  "i"(SPR_TBU), "i"(SPR_TB));
111
    // If there is a carry into the upper half, it is okay to return
112
    // (tbu1, 0) since it must be between the 2 TBU reads.
113
    tbl &= -static_cast<uint32>(tbu0 == tbu1);
114
    // high 32 bits in tbu1; low 32 bits in tbl  (tbu0 is garbage)
115
    time_base_value =
116
        (static_cast<uint64>(tbu1) << 32) | static_cast<uint64>(tbl);
117
  }
118
  return static_cast<int64>(time_base_value);
119
}
120
121
// ----------------------------------------------------------------
122
#elif defined(__sparc__)
123
inline int64 CycleClock::Now() {
124
  int64 tick;
125
  asm(".byte 0x83, 0x41, 0x00, 0x00");
126
  asm("mov   %%g1, %0" : "=r" (tick));
127
  return tick;
128
}
129
130
// ----------------------------------------------------------------
131
#elif defined(__ia64__)
132
inline int64 CycleClock::Now() {
133
  int64 itc;
134
  asm("mov %0 = ar.itc" : "=r" (itc));
135
  return itc;
136
}
137
138
// ----------------------------------------------------------------
139
#elif defined(_MSC_VER) && defined(_M_IX86)
140
inline int64 CycleClock::Now() {
141
  // Older MSVC compilers (like 7.x) don't seem to support the
142
  // __rdtsc intrinsic properly, so I prefer to use _asm instead
143
  // when I know it will work.  Otherwise, I'll use __rdtsc and hope
144
  // the code is being compiled with a non-ancient compiler.
145
  _asm rdtsc
146
}
147
148
// ----------------------------------------------------------------
149
#elif defined(_MSC_VER)
150
// For MSVC, we want to use '_asm rdtsc' when possible (since it works
151
// with even ancient MSVC compilers), and when not possible the
152
// __rdtsc intrinsic, declared in <intrin.h>.  Unfortunately, in some
153
// environments, <windows.h> and <intrin.h> have conflicting
154
// declarations of some other intrinsics, breaking compilation.
155
// Therefore, we simply declare __rdtsc ourselves. See also
156
// http://connect.microsoft.com/VisualStudio/feedback/details/262047
157
extern "C" uint64 __rdtsc();
158
#pragma intrinsic(__rdtsc)
159
inline int64 CycleClock::Now() {
160
  return __rdtsc();
161
}
162
163
// ----------------------------------------------------------------
164
#elif defined(__aarch64__)
165
#include "yb/gutil/sysinfo.h"
166
inline int64 CycleClock::Now() {
167
  // System timer of ARMv8 runs at a different frequency than the CPU's.
168
  // The frequency is fixed, typically in the range 1-50MHz.  It can be
169
  // read at CNTFRQ special register.  We assume the OS has set up
170
  // the virtual timer properly.
171
  int64_t virtual_timer_value;
172
  asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
173
  return virtual_timer_value;
174
}
175
176
// ----------------------------------------------------------------
177
#elif defined(ARMV6)  // V6 is the earliest arm that has a standard cyclecount
178
#include "yb/gutil/sysinfo.h"
179
inline int64 CycleClock::Now() {
180
  uint32 pmccntr;
181
  uint32 pmuseren;
182
  uint32 pmcntenset;
183
  // Read the user mode perf monitor counter access permissions.
184
  asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r" (pmuseren));
185
  if (pmuseren & 1) {  // Allows reading perfmon counters for user mode code.
186
    asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (pmcntenset));
187
    if (pmcntenset & 0x80000000ul) {  // Is it counting?
188
      asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (pmccntr));
189
      // The counter is set up to count every 64th cycle
190
      return static_cast<int64>(pmccntr) * 64;  // Should optimize to << 6
191
    }
192
  }
193
  struct timeval tv;
194
  gettimeofday(&tv, NULL);
195
  return static_cast<int64>((tv.tv_sec + tv.tv_usec * 0.000001)
196
                            * CyclesPerSecond());
197
}
198
199
// ----------------------------------------------------------------
200
#elif defined(ARMV3)
201
#include "yb/gutil/sysinfo.h"   // for CyclesPerSecond()
202
inline int64 CycleClock::Now() {
203
  struct timeval tv;
204
  gettimeofday(&tv, NULL);
205
  return static_cast<int64>((tv.tv_sec + tv.tv_usec * 0.000001)
206
                            * CyclesPerSecond());
207
}
208
209
// ----------------------------------------------------------------
210
#elif defined(__mips__)
211
#include "yb/gutil/sysinfo.h"
212
inline int64 CycleClock::Now() {
213
  // mips apparently only allows rdtsc for superusers, so we fall
214
  // back to gettimeofday.  It's possible clock_gettime would be better.
215
  struct timeval tv;
216
  gettimeofday(&tv, NULL);
217
  return static_cast<int64>((tv.tv_sec + tv.tv_usec * 0.000001)
218
                            * CyclesPerSecond());
219
}
220
221
// ----------------------------------------------------------------
222
#else
223
// The soft failover to a generic implementation is automatic only for some
224
// platforms.  For other platforms the developer is expected to make an attempt
225
// to create a fast implementation and use generic version if nothing better is
226
// available.
227
#error You need to define CycleTimer for your O/S and CPU
228
#endif
229
230
#endif  // GUTIL_CYCLECLOCK_INL_H_