xref: /aosp_15_r20/external/perfetto/src/base/time.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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