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