Loading...
Searching...
No Matches
timing.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_ARCH_TIMING_H
8#define PXR_BASE_ARCH_TIMING_H
9
13
14#include "pxr/pxr.h"
15#include "pxr/base/arch/api.h"
16#include "pxr/base/arch/defines.h"
18
21
22#if defined(ARCH_OS_LINUX) && defined(ARCH_CPU_INTEL)
23#include <x86intrin.h>
24#elif defined(ARCH_OS_DARWIN)
25#include <mach/mach_time.h>
26#elif defined(ARCH_OS_WINDOWS)
27#include <intrin.h>
28#endif
29
30#include <algorithm>
31#include <atomic>
32#include <iterator>
33#include <numeric>
34
35PXR_NAMESPACE_OPEN_SCOPE
36
44inline uint64_t
46{
47#if defined(ARCH_OS_DARWIN)
48 // On Darwin we'll use mach_absolute_time().
49 return mach_absolute_time();
50#elif defined(ARCH_CPU_INTEL)
51 // On Intel we'll use the rdtsc instruction.
52 return __rdtsc();
53#elif defined (ARCH_CPU_ARM)
54 uint64_t result;
55 #if defined(ARCH_COMPILER_MSVC)
56 // MSVC does not support inline assembly on ARM64 platforms
57 // 0x5F02 == ARM64_CNTVCT - manually calculated value avoids <windows.h>
58 result = _ReadStatusReg(0x5F02);
59 #else
60 __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
61 #endif
62 return result;
63#else
64#error Unknown architecture.
65#endif
66}
67
68
73inline uint64_t
75{
76 uint64_t t;
77#if defined (ARCH_OS_DARWIN) || \
78 (defined (ARCH_CPU_ARM) && defined (ARCH_COMPILER_MSVC))
79 return ArchGetTickTime();
80#elif defined (ARCH_CPU_ARM)
81 std::atomic_signal_fence(std::memory_order_seq_cst);
82 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
83 std::atomic_signal_fence(std::memory_order_seq_cst);
84#elif defined (ARCH_COMPILER_MSVC)
85 _mm_lfence();
86 std::atomic_signal_fence(std::memory_order_seq_cst);
87 t = __rdtsc();
88 _mm_lfence();
89 std::atomic_signal_fence(std::memory_order_seq_cst);
90#elif defined(ARCH_CPU_INTEL) && \
91 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
92 // Prevent reorders by the compiler.
93 std::atomic_signal_fence(std::memory_order_seq_cst);
94 asm volatile(
95 "lfence\n\t"
96 "rdtsc\n\t"
97 "shl $32, %%rdx\n\t"
98 "or %%rdx, %0\n\t"
99 "lfence"
100 : "=a"(t)
101 :
102 // rdtsc writes rdx
103 // shl modifies cc flags
104 : "rdx", "cc");
105#else
106#error "Unsupported architecture."
107#endif
108 return t;
109}
110
115inline uint64_t
117{
118 uint64_t t;
119#if defined (ARCH_OS_DARWIN) || \
120 (defined (ARCH_CPU_ARM) && defined (ARCH_COMPILER_MSVC))
121 return ArchGetTickTime();
122#elif defined (ARCH_CPU_ARM)
123 std::atomic_signal_fence(std::memory_order_seq_cst);
124 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
125 std::atomic_signal_fence(std::memory_order_seq_cst);
126#elif defined (ARCH_COMPILER_MSVC)
127 std::atomic_signal_fence(std::memory_order_seq_cst);
128 unsigned aux;
129 t = __rdtscp(&aux);
130 _mm_lfence();
131 std::atomic_signal_fence(std::memory_order_seq_cst);
132#elif defined(ARCH_CPU_INTEL) && \
133 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
134 std::atomic_signal_fence(std::memory_order_seq_cst);
135 asm volatile(
136 "rdtscp\n\t"
137 "shl $32, %%rdx\n\t"
138 "or %%rdx, %0\n\t"
139 "lfence"
140 : "=a"(t)
141 :
142 // rdtscp writes rcx & rdx
143 // shl modifies cc flags
144 : "rcx", "rdx", "cc");
145#else
146#error "Unsupported architecture."
147#endif
148 return t;
149}
150
151#if defined (doxygen) || \
152 (!defined(ARCH_OS_DARWIN) && defined(ARCH_CPU_INTEL) && \
153 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC)))
154
158{
160 explicit ArchIntervalTimer(bool start=true)
161 : _started(start) {
162 if (_started) {
163 Start();
164 }
165 }
166
168 void Start() {
169 _started = true;
170 std::atomic_signal_fence(std::memory_order_seq_cst);
171 asm volatile(
172 "lfence\n\t"
173 "rdtsc\n\t"
174 "lfence"
175 : "=a"(_startLow), "=d"(_startHigh) :: );
176 }
177
179 bool IsStarted() const {
180 return _started;
181 }
182
184 uint64_t GetStartTicks() const {
185 return (uint64_t(_startHigh) << 32) + _startLow;
186 }
187
189 uint64_t GetCurrentTicks() {
190 return ArchGetStopTickTime();
191 }
192
195 uint64_t GetElapsedTicks() {
196 if (!_started) {
197 return 0;
198 }
199 uint32_t stopLow, stopHigh;
200 std::atomic_signal_fence(std::memory_order_seq_cst);
201 asm volatile(
202 "rdtscp\n\t"
203 "lfence"
204 : "=a"(stopLow), "=d"(stopHigh)
205 :
206 // rdtscp writes rcx
207 : "rcx");
208 return ((uint64_t(stopHigh) << 32) + stopLow) -
209 ((uint64_t(_startHigh) << 32) + _startLow);
210 }
211private:
212 bool _started = false;
213 uint32_t _startLow = 0, _startHigh = 0;
214};
215
216#else
217
219{
220 explicit ArchIntervalTimer(bool start=true)
221 : _started(start) {
222 if (_started) {
223 _startTicks = ArchGetStartTickTime();
224 }
225 }
226
227 void Start() {
228 _started = true;
229 _startTicks = ArchGetStartTickTime();
230 }
231
232 bool IsStarted() const {
233 return _started;
234 }
235
236 uint64_t GetStartTicks() const {
237 return _startTicks;
238 }
239
240 uint64_t GetCurrentTicks() {
241 return ArchGetStopTickTime();
242 }
243
244 uint64_t GetElapsedTicks() {
245 if (!_started) {
246 return 0;
247 }
248 return ArchGetStopTickTime() - _startTicks;
249 }
250private:
251 bool _started = false;
252 uint64_t _startTicks;
253};
254
255#endif
256
267ARCH_API
269
272ARCH_API
274
275
288ARCH_API
289int64_t ArchTicksToNanoseconds(uint64_t nTicks);
290
293ARCH_API
294double ArchTicksToSeconds(uint64_t nTicks);
295
298ARCH_API
299uint64_t ArchSecondsToTicks(double seconds);
300
303ARCH_API
305
306ARCH_API
307uint64_t
308Arch_MeasureExecutionTime(uint64_t maxTicks, bool *reachedConsensus,
309 void const *m, uint64_t (*callM)(void const *, int));
310
320template <class Fn>
321uint64_t
323 Fn const &fn,
324 uint64_t maxTicks = 1e7,
325 bool *reachedConsensus = nullptr)
326{
327 auto measureN = [&fn](int nTimes) -> uint64_t {
328 ArchIntervalTimer iTimer;
329 for (int i = nTimes; i--; ) {
330 std::atomic_signal_fence(std::memory_order_seq_cst);
331 (void)fn();
332 std::atomic_signal_fence(std::memory_order_seq_cst);
333 }
334 return iTimer.GetElapsedTicks();
335 };
336
337 using MeasureNType = decltype(measureN);
338
339 return Arch_MeasureExecutionTime(
340 maxTicks, reachedConsensus,
341 static_cast<void const *>(&measureN),
342 [](void const *mN, int nTimes) {
343 return (*static_cast<MeasureNType const *>(mN))(nTimes);
344 });
345}
346
348
349PXR_NAMESPACE_CLOSE_SCOPE
350
351#endif // PXR_BASE_ARCH_TIMING_H
uint64_t ArchGetTickTime()
Return the current time in system-dependent units.
Definition: timing.h:45
ARCH_API uint64_t ArchGetTickQuantum()
Return the tick time resolution.
uint64_t ArchGetStartTickTime()
Get a "start" tick time for measuring an interval of time, followed by a later call to ArchGetStopTic...
Definition: timing.h:74
ARCH_API uint64_t ArchGetIntervalTimerTickOverhead()
Return the ticks taken to record an interval of time with ArchIntervalTimer, as measured at startup t...
ARCH_API double ArchGetNanosecondsPerTick()
Get nanoseconds per tick.
uint64_t ArchGetStopTickTime()
Get a "stop" tick time for measuring an interval of time.
Definition: timing.h:116
uint64_t ArchMeasureExecutionTime(Fn const &fn, uint64_t maxTicks=1e7, bool *reachedConsensus=nullptr)
Run fn repeatedly attempting to determine a consensus fastest execution time with low noise,...
Definition: timing.h:322
ARCH_API double ArchTicksToSeconds(uint64_t nTicks)
Convert a duration measured in "ticks", as returned by ArchGetTickTime(), to seconds.
ARCH_API uint64_t ArchSecondsToTicks(double seconds)
Convert a duration in seconds to "ticks", as returned by ArchGetTickTime().
ARCH_API int64_t ArchTicksToNanoseconds(uint64_t nTicks)
Convert a duration measured in "ticks", as returned by ArchGetTickTime(), to nanoseconds.
Define integral types.
A simple timer class for measuring an interval of time using the ArchTickTimer facilities.
Definition: timing.h:158
uint64_t GetCurrentTicks()
Read and return the current time.
Definition: timing.h:189
void Start()
Start the timer, or reset the start time if it has already been started.
Definition: timing.h:168
uint64_t GetStartTicks() const
Return this timer's start time, or 0 if it hasn't been started.
Definition: timing.h:184
uint64_t GetElapsedTicks()
Read the current time and return the difference between it and the start time.
Definition: timing.h:195
ArchIntervalTimer(bool start=true)
Construct a timer and start timing if start is true.
Definition: timing.h:160
bool IsStarted() const
Return true if this timer is started.
Definition: timing.h:179