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