Pixar Arch
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 __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
52 return result;
53#else
54#error Unknown architecture.
55#endif
56}
57
58
63inline uint64_t
65{
66 uint64_t t;
67#if defined (ARCH_OS_DARWIN)
68 return ArchGetTickTime();
69#elif defined (ARCH_CPU_ARM)
70 std::atomic_signal_fence(std::memory_order_seq_cst);
71 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
72 std::atomic_signal_fence(std::memory_order_seq_cst);
73#elif defined (ARCH_COMPILER_MSVC)
74 _mm_lfence();
75 std::atomic_signal_fence(std::memory_order_seq_cst);
76 t = __rdtsc();
77 _mm_lfence();
78 std::atomic_signal_fence(std::memory_order_seq_cst);
79#elif defined(ARCH_CPU_INTEL) && \
80 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
81 // Prevent reorders by the compiler.
82 std::atomic_signal_fence(std::memory_order_seq_cst);
83 asm volatile(
84 "lfence\n\t"
85 "rdtsc\n\t"
86 "shl $32, %%rdx\n\t"
87 "or %%rdx, %0\n\t"
88 "lfence"
89 : "=a"(t)
90 :
91 // rdtsc writes rdx
92 // shl modifies cc flags
93 : "rdx", "cc");
94#else
95#error "Unsupported architecture."
96#endif
97 return t;
98}
99
104inline uint64_t
106{
107 uint64_t t;
108#if defined (ARCH_OS_DARWIN)
109 return ArchGetTickTime();
110#elif defined (ARCH_CPU_ARM)
111 std::atomic_signal_fence(std::memory_order_seq_cst);
112 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
113 std::atomic_signal_fence(std::memory_order_seq_cst);
114#elif defined (ARCH_COMPILER_MSVC)
115 std::atomic_signal_fence(std::memory_order_seq_cst);
116 unsigned aux;
117 t = __rdtscp(&aux);
118 _mm_lfence();
119 std::atomic_signal_fence(std::memory_order_seq_cst);
120#elif defined(ARCH_CPU_INTEL) && \
121 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
122 std::atomic_signal_fence(std::memory_order_seq_cst);
123 asm volatile(
124 "rdtscp\n\t"
125 "shl $32, %%rdx\n\t"
126 "or %%rdx, %0\n\t"
127 "lfence"
128 : "=a"(t)
129 :
130 // rdtscp writes rcx & rdx
131 // shl modifies cc flags
132 : "rcx", "rdx", "cc");
133#else
134#error "Unsupported architecture."
135#endif
136 return t;
137}
138
139#if defined (doxygen) || \
140 (!defined(ARCH_OS_DARWIN) && defined(ARCH_CPU_INTEL) && \
141 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC)))
142
146{
148 explicit ArchIntervalTimer(bool start=true)
149 : _started(start) {
150 if (_started) {
151 Start();
152 }
153 }
154
156 void Start() {
157 _started = true;
158 std::atomic_signal_fence(std::memory_order_seq_cst);
159 asm volatile(
160 "lfence\n\t"
161 "rdtsc\n\t"
162 "lfence"
163 : "=a"(_startLow), "=d"(_startHigh) :: );
164 }
165
167 bool IsStarted() const {
168 return _started;
169 }
170
172 uint64_t GetStartTicks() const {
173 return (uint64_t(_startHigh) << 32) + _startLow;
174 }
175
177 uint64_t GetCurrentTicks() {
178 return ArchGetStopTickTime();
179 }
180
183 uint64_t GetElapsedTicks() {
184 if (!_started) {
185 return 0;
186 }
187 uint32_t stopLow, stopHigh;
188 std::atomic_signal_fence(std::memory_order_seq_cst);
189 asm volatile(
190 "rdtscp\n\t"
191 "lfence"
192 : "=a"(stopLow), "=d"(stopHigh)
193 :
194 // rdtscp writes rcx
195 : "rcx");
196 return ((uint64_t(stopHigh) << 32) + stopLow) -
197 ((uint64_t(_startHigh) << 32) + _startLow);
198 }
199private:
200 bool _started = false;
201 uint32_t _startLow = 0, _startHigh = 0;
202};
203
204#else
205
206struct ArchIntervalTimer
207{
208 explicit ArchIntervalTimer(bool start=true)
209 : _started(start) {
210 if (_started) {
211 _startTicks = ArchGetStartTickTime();
212 }
213 }
214
215 void Start() {
216 _started = true;
217 _startTicks = ArchGetStartTickTime();
218 }
219
220 bool IsStarted() const {
221 return _started;
222 }
223
224 uint64_t GetStartTicks() const {
225 return _startTicks;
226 }
227
228 uint64_t GetCurrentTicks() {
229 return ArchGetStopTickTime();
230 }
231
232 uint64_t GetElapsedTicks() {
233 if (!_started) {
234 return 0;
235 }
236 return ArchGetStopTickTime() - _startTicks;
237 }
238private:
239 bool _started = false;
240 uint64_t _startTicks;
241};
242
243#endif
244
255ARCH_API
257
260ARCH_API
262
263
276ARCH_API
277int64_t ArchTicksToNanoseconds(uint64_t nTicks);
278
281ARCH_API
282double ArchTicksToSeconds(uint64_t nTicks);
283
286ARCH_API
287uint64_t ArchSecondsToTicks(double seconds);
288
291ARCH_API
293
294ARCH_API
295uint64_t
296Arch_MeasureExecutionTime(uint64_t maxTicks, bool *reachedConsensus,
297 void const *m, uint64_t (*callM)(void const *, int));
298
308template <class Fn>
309uint64_t
311 Fn const &fn,
312 uint64_t maxTicks = 1e7,
313 bool *reachedConsensus = nullptr)
314{
315 auto measureN = [&fn](int nTimes) -> uint64_t {
316 ArchIntervalTimer iTimer;
317 for (int i = nTimes; i--; ) {
318 std::atomic_signal_fence(std::memory_order_seq_cst);
319 (void)fn();
320 std::atomic_signal_fence(std::memory_order_seq_cst);
321 }
322 return iTimer.GetElapsedTicks();
323 };
324
325 using MeasureNType = decltype(measureN);
326
328 maxTicks, reachedConsensus,
329 static_cast<void const *>(&measureN),
330 [](void const *mN, int nTimes) {
331 return (*static_cast<MeasureNType const *>(mN))(nTimes);
332 });
333}
334
335} // namespace pxr
336
337#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:64
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:310
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:105
A simple timer class for measuring an interval of time using the ArchTickTimer facilities.
Definition timing.h:146
uint64_t GetStartTicks() const
Return this timer's start time, or 0 if it hasn't been started.
Definition timing.h:172
void Start()
Start the timer, or reset the start time if it has already been started.
Definition timing.h:156
bool IsStarted() const
Return true if this timer is started.
Definition timing.h:167
ArchIntervalTimer(bool start=true)
Construct a timer and start timing if start is true.
Definition timing.h:148
uint64_t GetCurrentTicks()
Read and return the current time.
Definition timing.h:177
uint64_t GetElapsedTicks()
Read the current time and return the difference between it and the start time.
Definition timing.h:183