1// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "absl/base/internal/unscaledcycleclock.h"
16
17#if ABSL_USE_UNSCALED_CYCLECLOCK
18
19#if defined(_WIN32)
20#include <intrin.h>
21#endif
22
23#if defined(__powerpc__) || defined(__ppc__)
24#include <sys/platform/ppc.h>
25#endif
26
27#include "absl/base/internal/sysinfo.h"
28
29namespace absl {
30namespace base_internal {
31
32#if defined(__i386__)
33
34int64_t UnscaledCycleClock::Now() {
35 int64_t ret;
36 __asm__ volatile("rdtsc" : "=A"(ret));
37 return ret;
38}
39
40double UnscaledCycleClock::Frequency() {
41 return base_internal::NominalCPUFrequency();
42}
43
44#elif defined(__x86_64__)
45
46int64_t UnscaledCycleClock::Now() {
47 uint64_t low, high;
48 __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
49 return (high << 32) | low;
50}
51
52double UnscaledCycleClock::Frequency() {
53 return base_internal::NominalCPUFrequency();
54}
55
56#elif defined(__powerpc__) || defined(__ppc__)
57
58int64_t UnscaledCycleClock::Now() {
59 return __ppc_get_timebase();
60}
61
62double UnscaledCycleClock::Frequency() {
63 return __ppc_get_timebase_freq();
64}
65
66#elif defined(__aarch64__)
67
68// System timer of ARMv8 runs at a different frequency than the CPU's.
69// The frequency is fixed, typically in the range 1-50MHz. It can be
70// read at CNTFRQ special register. We assume the OS has set up
71// the virtual timer properly.
72int64_t UnscaledCycleClock::Now() {
73 int64_t virtual_timer_value;
74 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
75 return virtual_timer_value;
76}
77
78double UnscaledCycleClock::Frequency() {
79 uint64_t aarch64_timer_frequency;
80 asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency));
81 return aarch64_timer_frequency;
82}
83
84#elif defined(_M_IX86) || defined(_M_X64)
85
86#pragma intrinsic(__rdtsc)
87
88int64_t UnscaledCycleClock::Now() {
89 return __rdtsc();
90}
91
92double UnscaledCycleClock::Frequency() {
93 return base_internal::NominalCPUFrequency();
94}
95
96#endif
97
98} // namespace base_internal
99} // namespace absl
100
101#endif // ABSL_USE_UNSCALED_CYCLECLOCK
102