1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <atomic>
18
19 #include "perfetto/base/time.h"
20
21 #include "perfetto/base/build_config.h"
22 #include "perfetto/base/logging.h"
23 #include "perfetto/ext/base/string_utils.h"
24
25 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
26 #include <Windows.h>
27 #else
28 #include <unistd.h>
29 #endif
30
31 namespace perfetto {
32 namespace base {
33
34 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
35 #if !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
36 namespace {
37
38 // Returns the current value of the performance counter.
QPCNowRaw()39 int64_t QPCNowRaw() {
40 LARGE_INTEGER perf_counter_now = {};
41 // According to the MSDN documentation for QueryPerformanceCounter(), this
42 // will never fail on systems that run XP or later.
43 // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
44 ::QueryPerformanceCounter(&perf_counter_now);
45 return perf_counter_now.QuadPart;
46 }
47
TSCTicksPerSecond()48 double TSCTicksPerSecond() {
49 // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
50 // frequency, because there is no guarantee that the TSC frequency is equal to
51 // the performance counter frequency.
52 // The TSC frequency is cached in a static variable because it takes some time
53 // to compute it.
54 static std::atomic<double> tsc_ticks_per_second = 0;
55 double value = tsc_ticks_per_second.load(std::memory_order_relaxed);
56 if (value != 0)
57 return value;
58
59 // Increase the thread priority to reduces the chances of having a context
60 // switch during a reading of the TSC and the performance counter.
61 const int previous_priority = ::GetThreadPriority(::GetCurrentThread());
62 ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
63
64 // The first time that this function is called, make an initial reading of the
65 // TSC and the performance counter. Initialization of static variable is
66 // thread-safe. Threads can race initializing tsc_initial vs
67 // perf_counter_initial, although they should be storing very similar values.
68
69 static const uint64_t tsc_initial = __rdtsc();
70 static const int64_t perf_counter_initial = QPCNowRaw();
71
72 // Make a another reading of the TSC and the performance counter every time
73 // that this function is called.
74 const uint64_t tsc_now = __rdtsc();
75 const int64_t perf_counter_now = QPCNowRaw();
76
77 // Reset the thread priority.
78 ::SetThreadPriority(::GetCurrentThread(), previous_priority);
79
80 // Make sure that at least 50 ms elapsed between the 2 readings. The first
81 // time that this function is called, we don't expect this to be the case.
82 // Note: The longer the elapsed time between the 2 readings is, the more
83 // accurate the computed TSC frequency will be. The 50 ms value was
84 // chosen because local benchmarks show that it allows us to get a
85 // stddev of less than 1 tick/us between multiple runs.
86 // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
87 // this will never fail on systems that run XP or later.
88 // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
89 LARGE_INTEGER perf_counter_frequency = {};
90 ::QueryPerformanceFrequency(&perf_counter_frequency);
91 PERFETTO_CHECK(perf_counter_now >= perf_counter_initial);
92 const int64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
93 const double elapsed_time_seconds =
94 static_cast<double>(perf_counter_ticks) /
95 static_cast<double>(perf_counter_frequency.QuadPart);
96
97 constexpr double kMinimumEvaluationPeriodSeconds = 0.05;
98 if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
99 return 0;
100
101 // Compute the frequency of the TSC.
102 PERFETTO_CHECK(tsc_now >= tsc_initial);
103 const uint64_t tsc_ticks = tsc_now - tsc_initial;
104 // Racing with another thread to write |tsc_ticks_per_second| is benign
105 // because both threads will write a valid result.
106 tsc_ticks_per_second.store(
107 static_cast<double>(tsc_ticks) / elapsed_time_seconds,
108 std::memory_order_relaxed);
109
110 return tsc_ticks_per_second.load(std::memory_order_relaxed);
111 }
112
113 } // namespace
114 #endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
115
GetWallTimeNs()116 TimeNanos GetWallTimeNs() {
117 LARGE_INTEGER freq;
118 ::QueryPerformanceFrequency(&freq);
119 LARGE_INTEGER counter;
120 ::QueryPerformanceCounter(&counter);
121 double elapsed_nanoseconds = (1e9 * static_cast<double>(counter.QuadPart)) /
122 static_cast<double>(freq.QuadPart);
123 return TimeNanos(static_cast<uint64_t>(elapsed_nanoseconds));
124 }
125
GetThreadCPUTimeNs()126 TimeNanos GetThreadCPUTimeNs() {
127 #if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
128 // QueryThreadCycleTime versus TSCTicksPerSecond doesn't have much relation to
129 // actual elapsed time on Windows on Arm, because QueryThreadCycleTime is
130 // backed by the actual number of CPU cycles executed, rather than a
131 // constant-rate timer like Intel. To work around this, use GetThreadTimes
132 // (which isn't as accurate but is meaningful as a measure of elapsed
133 // per-thread time).
134 FILETIME dummy, kernel_ftime, user_ftime;
135 ::GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel_ftime,
136 &user_ftime);
137 uint64_t kernel_time =
138 kernel_ftime.dwHighDateTime * 0x100000000 + kernel_ftime.dwLowDateTime;
139 uint64_t user_time =
140 user_ftime.dwHighDateTime * 0x100000000 + user_ftime.dwLowDateTime;
141
142 return TimeNanos((kernel_time + user_time) * 100);
143 #else // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
144 // Get the number of TSC ticks used by the current thread.
145 ULONG64 thread_cycle_time = 0;
146 ::QueryThreadCycleTime(GetCurrentThread(), &thread_cycle_time);
147
148 // Get the frequency of the TSC.
149 const double tsc_ticks_per_second = TSCTicksPerSecond();
150 if (tsc_ticks_per_second == 0)
151 return TimeNanos();
152
153 // Return the CPU time of the current thread.
154 const double thread_time_seconds =
155 static_cast<double>(thread_cycle_time) / tsc_ticks_per_second;
156 constexpr int64_t kNanosecondsPerSecond = 1000 * 1000 * 1000;
157 return TimeNanos(
158 static_cast<int64_t>(thread_time_seconds * kNanosecondsPerSecond));
159 #endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
160 }
161
SleepMicroseconds(unsigned interval_us)162 void SleepMicroseconds(unsigned interval_us) {
163 // The Windows Sleep function takes a millisecond count. Round up so that
164 // short sleeps don't turn into a busy wait. Note that the sleep granularity
165 // on Windows can dynamically vary from 1 ms to ~16 ms, so don't count on this
166 // being a short sleep.
167 ::Sleep(static_cast<DWORD>((interval_us + 999) / 1000));
168 }
169
InitializeTime()170 void InitializeTime() {
171 #if !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
172 // Make an early first call to TSCTicksPerSecond() to start 50 ms elapsed time
173 // (see comment in TSCTicksPerSecond()).
174 TSCTicksPerSecond();
175 #endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
176 }
177
178 #else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
179
180 void SleepMicroseconds(unsigned interval_us) {
181 ::usleep(static_cast<useconds_t>(interval_us));
182 }
183
184 void InitializeTime() {}
185
186 #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
187
GetTimeFmt(const std::string & fmt)188 std::string GetTimeFmt(const std::string& fmt) {
189 time_t raw_time;
190 time(&raw_time);
191 struct tm local_tm;
192 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
193 PERFETTO_CHECK(localtime_s(&local_tm, &raw_time) == 0);
194 #else
195 tzset();
196 PERFETTO_CHECK(localtime_r(&raw_time, &local_tm) != nullptr);
197 #endif
198 char buf[128];
199 PERFETTO_CHECK(strftime(buf, 80, fmt.c_str(), &local_tm) > 0);
200 return buf;
201 }
202
GetTimezoneOffsetMins()203 std::optional<int32_t> GetTimezoneOffsetMins() {
204 std::string tz = GetTimeFmt("%z");
205 if (tz.size() != 5 || (tz[0] != '+' && tz[0] != '-'))
206 return std::nullopt;
207 char sign = '\0';
208 int32_t hh = 0;
209 int32_t mm = 0;
210 if (sscanf(tz.c_str(), "%c%2d%2d", &sign, &hh, &mm) != 3)
211 return std::nullopt;
212 return (hh * 60 + mm) * (sign == '-' ? -1 : 1);
213 }
214
215 } // namespace base
216 } // namespace perfetto
217