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_WASM_VM)
25#include <emscripten.h>
26#elif defined(ARCH_OS_DARWIN)
27#include <mach/mach_time.h>
28#elif defined(ARCH_OS_WINDOWS)
29#include <intrin.h>
30#endif
31
32#include <algorithm>
33#include <atomic>
34#include <iterator>
35#include <numeric>
36
37PXR_NAMESPACE_OPEN_SCOPE
38
46inline uint64_t
48{
49#if defined(ARCH_OS_DARWIN)
50 // On Darwin we'll use mach_absolute_time().
51 return mach_absolute_time();
52#elif defined(ARCH_CPU_INTEL)
53 // On Intel we'll use the rdtsc instruction.
54 return __rdtsc();
55#elif defined (ARCH_CPU_ARM)
56 uint64_t result;
57 #if defined(ARCH_COMPILER_MSVC)
58 // MSVC does not support inline assembly on ARM64 platforms
59 // 0x5F02 == ARM64_CNTVCT - manually calculated value avoids <windows.h>
60 result = _ReadStatusReg(0x5F02);
61 #else
62 __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
63 #endif
64 return result;
65#elif defined(ARCH_OS_WASM_VM)
66 return static_cast<int64_t>(emscripten_get_now() * 1e+6);
67#else
68#error Unknown architecture.
69#endif
70}
71
72
77inline uint64_t
79{
80 uint64_t t;
81#if defined (ARCH_OS_DARWIN) || defined(ARCH_OS_WASM_VM) || \
82 (defined (ARCH_CPU_ARM) && defined (ARCH_COMPILER_MSVC))
83 return ArchGetTickTime();
84#elif defined (ARCH_CPU_ARM)
85 std::atomic_signal_fence(std::memory_order_seq_cst);
86 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
87 std::atomic_signal_fence(std::memory_order_seq_cst);
88#elif defined (ARCH_COMPILER_MSVC)
89 _mm_lfence();
90 std::atomic_signal_fence(std::memory_order_seq_cst);
91 t = __rdtsc();
92 _mm_lfence();
93 std::atomic_signal_fence(std::memory_order_seq_cst);
94#elif defined(ARCH_CPU_INTEL) && \
95 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
96 // Prevent reorders by the compiler.
97 std::atomic_signal_fence(std::memory_order_seq_cst);
98 asm volatile(
99 "lfence\n\t"
100 "rdtsc\n\t"
101 "shl $32, %%rdx\n\t"
102 "or %%rdx, %0\n\t"
103 "lfence"
104 : "=a"(t)
105 :
106 // rdtsc writes rdx
107 // shl modifies cc flags
108 : "rdx", "cc");
109#else
110#error "Unsupported architecture."
111#endif
112 return t;
113}
114
119inline uint64_t
121{
122 uint64_t t;
123#if defined (ARCH_OS_DARWIN) || defined(ARCH_OS_WASM_VM) || \
124 (defined (ARCH_CPU_ARM) && defined (ARCH_COMPILER_MSVC))
125 return ArchGetTickTime();
126#elif defined (ARCH_CPU_ARM)
127 std::atomic_signal_fence(std::memory_order_seq_cst);
128 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
129 std::atomic_signal_fence(std::memory_order_seq_cst);
130#elif defined (ARCH_COMPILER_MSVC)
131 std::atomic_signal_fence(std::memory_order_seq_cst);
132 unsigned aux;
133 t = __rdtscp(&aux);
134 _mm_lfence();
135 std::atomic_signal_fence(std::memory_order_seq_cst);
136#elif defined(ARCH_CPU_INTEL) && \
137 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
138 std::atomic_signal_fence(std::memory_order_seq_cst);
139 asm volatile(
140 "rdtscp\n\t"
141 "shl $32, %%rdx\n\t"
142 "or %%rdx, %0\n\t"
143 "lfence"
144 : "=a"(t)
145 :
146 // rdtscp writes rcx & rdx
147 // shl modifies cc flags
148 : "rcx", "rdx", "cc");
149#else
150#error "Unsupported architecture."
151#endif
152 return t;
153}
154
155#if defined (doxygen) || \
156 (!defined(ARCH_OS_DARWIN) && defined(ARCH_CPU_INTEL) && \
157 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC)))
158
162{
164 explicit ArchIntervalTimer(bool start=true)
165 : _started(start) {
166 if (_started) {
167 Start();
168 }
169 }
170
172 void Start() {
173 _started = true;
174 std::atomic_signal_fence(std::memory_order_seq_cst);
175 asm volatile(
176 "lfence\n\t"
177 "rdtsc\n\t"
178 "lfence"
179 : "=a"(_startLow), "=d"(_startHigh) :: );
180 }
181
183 bool IsStarted() const {
184 return _started;
185 }
186
188 uint64_t GetStartTicks() const {
189 return (uint64_t(_startHigh) << 32) + _startLow;
190 }
191
193 uint64_t GetCurrentTicks() {
194 return ArchGetStopTickTime();
195 }
196
199 uint64_t GetElapsedTicks() {
200 if (!_started) {
201 return 0;
202 }
203 uint32_t stopLow, stopHigh;
204 std::atomic_signal_fence(std::memory_order_seq_cst);
205 asm volatile(
206 "rdtscp\n\t"
207 "lfence"
208 : "=a"(stopLow), "=d"(stopHigh)
209 :
210 // rdtscp writes rcx
211 : "rcx");
212 return ((uint64_t(stopHigh) << 32) + stopLow) -
213 ((uint64_t(_startHigh) << 32) + _startLow);
214 }
215private:
216 bool _started = false;
217 uint32_t _startLow = 0, _startHigh = 0;
218};
219
220#else
221
223{
224 explicit ArchIntervalTimer(bool start=true)
225 : _started(start) {
226 if (_started) {
227 _startTicks = ArchGetStartTickTime();
228 }
229 }
230
231 void Start() {
232 _started = true;
233 _startTicks = ArchGetStartTickTime();
234 }
235
236 bool IsStarted() const {
237 return _started;
238 }
239
240 uint64_t GetStartTicks() const {
241 return _startTicks;
242 }
243
244 uint64_t GetCurrentTicks() {
245 return ArchGetStopTickTime();
246 }
247
248 uint64_t GetElapsedTicks() {
249 if (!_started) {
250 return 0;
251 }
252 return ArchGetStopTickTime() - _startTicks;
253 }
254private:
255 bool _started = false;
256 uint64_t _startTicks;
257};
258
259#endif
260
271ARCH_API
273
276ARCH_API
278
279
292ARCH_API
293int64_t ArchTicksToNanoseconds(uint64_t nTicks);
294
297ARCH_API
298double ArchTicksToSeconds(uint64_t nTicks);
299
302ARCH_API
303uint64_t ArchSecondsToTicks(double seconds);
304
307ARCH_API
309
310ARCH_API
311uint64_t
312Arch_MeasureExecutionTime(uint64_t maxTicks, bool *reachedConsensus,
313 void const *m, uint64_t (*callM)(void const *, int));
314
324template <class Fn>
325uint64_t
327 Fn const &fn,
328 uint64_t maxTicks = 1e7,
329 bool *reachedConsensus = nullptr)
330{
331 auto measureN = [&fn](int nTimes) -> uint64_t {
332 ArchIntervalTimer iTimer;
333 for (int i = nTimes; i--; ) {
334 std::atomic_signal_fence(std::memory_order_seq_cst);
335 (void)fn();
336 std::atomic_signal_fence(std::memory_order_seq_cst);
337 }
338 return iTimer.GetElapsedTicks();
339 };
340
341 using MeasureNType = decltype(measureN);
342
343 return Arch_MeasureExecutionTime(
344 maxTicks, reachedConsensus,
345 static_cast<void const *>(&measureN),
346 [](void const *mN, int nTimes) {
347 return (*static_cast<MeasureNType const *>(mN))(nTimes);
348 });
349}
350
352
353PXR_NAMESPACE_CLOSE_SCOPE
354
355#endif // PXR_BASE_ARCH_TIMING_H
uint64_t ArchGetTickTime()
Return the current time in system-dependent units.
Definition: timing.h:47
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:78
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:120
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:326
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:162
uint64_t GetCurrentTicks()
Read and return the current time.
Definition: timing.h:193
void Start()
Start the timer, or reset the start time if it has already been started.
Definition: timing.h:172
uint64_t GetStartTicks() const
Return this timer's start time, or 0 if it hasn't been started.
Definition: timing.h:188
uint64_t GetElapsedTicks()
Read the current time and return the difference between it and the start time.
Definition: timing.h:199
ArchIntervalTimer(bool start=true)
Construct a timer and start timing if start is true.
Definition: timing.h:164
bool IsStarted() const
Return true if this timer is started.
Definition: timing.h:183