All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
56 return result;
57#else
58#error Unknown architecture.
59#endif
60}
61
62
67inline uint64_t
69{
70 uint64_t t;
71#if defined (ARCH_OS_DARWIN)
72 return ArchGetTickTime();
73#elif defined (ARCH_CPU_ARM)
74 std::atomic_signal_fence(std::memory_order_seq_cst);
75 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
76 std::atomic_signal_fence(std::memory_order_seq_cst);
77#elif defined (ARCH_COMPILER_MSVC)
78 _mm_lfence();
79 std::atomic_signal_fence(std::memory_order_seq_cst);
80 t = __rdtsc();
81 _mm_lfence();
82 std::atomic_signal_fence(std::memory_order_seq_cst);
83#elif defined(ARCH_CPU_INTEL) && \
84 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
85 // Prevent reorders by the compiler.
86 std::atomic_signal_fence(std::memory_order_seq_cst);
87 asm volatile(
88 "lfence\n\t"
89 "rdtsc\n\t"
90 "shl $32, %%rdx\n\t"
91 "or %%rdx, %0\n\t"
92 "lfence"
93 : "=a"(t)
94 :
95 // rdtsc writes rdx
96 // shl modifies cc flags
97 : "rdx", "cc");
98#else
99#error "Unsupported architecture."
100#endif
101 return t;
102}
103
108inline uint64_t
110{
111 uint64_t t;
112#if defined (ARCH_OS_DARWIN)
113 return ArchGetTickTime();
114#elif defined (ARCH_CPU_ARM)
115 std::atomic_signal_fence(std::memory_order_seq_cst);
116 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
117 std::atomic_signal_fence(std::memory_order_seq_cst);
118#elif defined (ARCH_COMPILER_MSVC)
119 std::atomic_signal_fence(std::memory_order_seq_cst);
120 unsigned aux;
121 t = __rdtscp(&aux);
122 _mm_lfence();
123 std::atomic_signal_fence(std::memory_order_seq_cst);
124#elif defined(ARCH_CPU_INTEL) && \
125 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
126 std::atomic_signal_fence(std::memory_order_seq_cst);
127 asm volatile(
128 "rdtscp\n\t"
129 "shl $32, %%rdx\n\t"
130 "or %%rdx, %0\n\t"
131 "lfence"
132 : "=a"(t)
133 :
134 // rdtscp writes rcx & rdx
135 // shl modifies cc flags
136 : "rcx", "rdx", "cc");
137#else
138#error "Unsupported architecture."
139#endif
140 return t;
141}
142
143#if defined (doxygen) || \
144 (!defined(ARCH_OS_DARWIN) && defined(ARCH_CPU_INTEL) && \
145 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC)))
146
150{
152 explicit ArchIntervalTimer(bool start=true)
153 : _started(start) {
154 if (_started) {
155 Start();
156 }
157 }
158
160 void Start() {
161 _started = true;
162 std::atomic_signal_fence(std::memory_order_seq_cst);
163 asm volatile(
164 "lfence\n\t"
165 "rdtsc\n\t"
166 "lfence"
167 : "=a"(_startLow), "=d"(_startHigh) :: );
168 }
169
171 bool IsStarted() const {
172 return _started;
173 }
174
176 uint64_t GetStartTicks() const {
177 return (uint64_t(_startHigh) << 32) + _startLow;
178 }
179
181 uint64_t GetCurrentTicks() {
182 return ArchGetStopTickTime();
183 }
184
187 uint64_t GetElapsedTicks() {
188 if (!_started) {
189 return 0;
190 }
191 uint32_t stopLow, stopHigh;
192 std::atomic_signal_fence(std::memory_order_seq_cst);
193 asm volatile(
194 "rdtscp\n\t"
195 "lfence"
196 : "=a"(stopLow), "=d"(stopHigh)
197 :
198 // rdtscp writes rcx
199 : "rcx");
200 return ((uint64_t(stopHigh) << 32) + stopLow) -
201 ((uint64_t(_startHigh) << 32) + _startLow);
202 }
203private:
204 bool _started = false;
205 uint32_t _startLow = 0, _startHigh = 0;
206};
207
208#else
209
211{
212 explicit ArchIntervalTimer(bool start=true)
213 : _started(start) {
214 if (_started) {
215 _startTicks = ArchGetStartTickTime();
216 }
217 }
218
219 void Start() {
220 _started = true;
221 _startTicks = ArchGetStartTickTime();
222 }
223
224 bool IsStarted() const {
225 return _started;
226 }
227
228 uint64_t GetStartTicks() const {
229 return _startTicks;
230 }
231
232 uint64_t GetCurrentTicks() {
233 return ArchGetStopTickTime();
234 }
235
236 uint64_t GetElapsedTicks() {
237 if (!_started) {
238 return 0;
239 }
240 return ArchGetStopTickTime() - _startTicks;
241 }
242private:
243 bool _started = false;
244 uint64_t _startTicks;
245};
246
247#endif
248
259ARCH_API
261
264ARCH_API
266
267
280ARCH_API
281int64_t ArchTicksToNanoseconds(uint64_t nTicks);
282
285ARCH_API
286double ArchTicksToSeconds(uint64_t nTicks);
287
290ARCH_API
291uint64_t ArchSecondsToTicks(double seconds);
292
295ARCH_API
297
298ARCH_API
299uint64_t
300Arch_MeasureExecutionTime(uint64_t maxTicks, bool *reachedConsensus,
301 void const *m, uint64_t (*callM)(void const *, int));
302
312template <class Fn>
313uint64_t
315 Fn const &fn,
316 uint64_t maxTicks = 1e7,
317 bool *reachedConsensus = nullptr)
318{
319 auto measureN = [&fn](int nTimes) -> uint64_t {
320 ArchIntervalTimer iTimer;
321 for (int i = nTimes; i--; ) {
322 std::atomic_signal_fence(std::memory_order_seq_cst);
323 (void)fn();
324 std::atomic_signal_fence(std::memory_order_seq_cst);
325 }
326 return iTimer.GetElapsedTicks();
327 };
328
329 using MeasureNType = decltype(measureN);
330
331 return Arch_MeasureExecutionTime(
332 maxTicks, reachedConsensus,
333 static_cast<void const *>(&measureN),
334 [](void const *mN, int nTimes) {
335 return (*static_cast<MeasureNType const *>(mN))(nTimes);
336 });
337}
338
340
341PXR_NAMESPACE_CLOSE_SCOPE
342
343#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:68
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:109
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:314
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:150
uint64_t GetCurrentTicks()
Read and return the current time.
Definition: timing.h:181
void Start()
Start the timer, or reset the start time if it has already been started.
Definition: timing.h:160
uint64_t GetStartTicks() const
Return this timer's start time, or 0 if it hasn't been started.
Definition: timing.h:176
uint64_t GetElapsedTicks()
Read the current time and return the difference between it and the start time.
Definition: timing.h:187
ArchIntervalTimer(bool start=true)
Construct a timer and start timing if start is true.
Definition: timing.h:152
bool IsStarted() const
Return true if this timer is started.
Definition: timing.h:171