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// See if we should use the x86 TSC register for timing.
23#if defined(PXR_ARCH_PREFER_TSC_TIMING) && \
24 defined(ARCH_OS_LINUX) && \
25 defined(ARCH_CPU_INTEL) && \
26 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
27#define ARCH_USE_TSC_TIMING 1
28#else
29#define ARCH_USE_TSC_TIMING 0
30#endif
31
32#if ARCH_USE_TSC_TIMING
33#include <x86intrin.h>
34#endif
35
36#include <atomic>
37#include <chrono>
38#include <cmath>
39
40// XXX: None of <algorithm>, <iterator>, nor <numeric> are used by the timing
41// routines, but the includes have been here forever and removing them causes
42// other code that is not including all the headers it needs to fail to compile.
43// These should be deprecated and removed.
44#include <algorithm>
45#include <iterator>
46#include <numeric>
47
48PXR_NAMESPACE_OPEN_SCOPE
49
50// Use a std::chrono clock if we're not using the Intel RDTSC instruction
51#if !ARCH_USE_TSC_TIMING
56using Arch_TimingClock = std::chrono::steady_clock;
57#endif
58
66inline uint64_t
68{
69#if ARCH_USE_TSC_TIMING
70 return __rdtsc();
71#else
72 return Arch_TimingClock::now().time_since_epoch().count();
73#endif
74}
75
76
81inline uint64_t
83{
84 uint64_t t;
85
86#if ARCH_USE_TSC_TIMING
87
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
102#else
103
104 std::atomic_signal_fence(std::memory_order_seq_cst);
105 t = ArchGetTickTime();
106 std::atomic_signal_fence(std::memory_order_seq_cst);
107
108#endif
109
110 return t;
111}
112
117inline uint64_t
119{
120 uint64_t t;
121
122#if ARCH_USE_TSC_TIMING
123
124 // Prevent reorders by the compiler.
125 std::atomic_signal_fence(std::memory_order_seq_cst);
126 asm volatile(
127 "rdtscp\n\t"
128 "shl $32, %%rdx\n\t"
129 "or %%rdx, %0\n\t"
130 "lfence"
131 : "=a"(t)
132 :
133 // rdtscp writes rcx & rdx
134 // shl modifies cc flags
135 : "rcx", "rdx", "cc");
136
137#else
138
139 std::atomic_signal_fence(std::memory_order_seq_cst);
140 t = ArchGetTickTime();
141 std::atomic_signal_fence(std::memory_order_seq_cst);
142
143#endif
144
145 return t;
146}
147
151{
152 explicit ArchIntervalTimer(bool start=true)
153 : _started(start) {
154 if (_started) {
155 _startTicks = ArchGetStartTickTime();
156 }
157 }
158
159 void Start() {
160 _started = true;
161 _startTicks = ArchGetStartTickTime();
162 }
163
164 bool IsStarted() const {
165 return _started;
166 }
167
168 uint64_t GetStartTicks() const {
169 return _startTicks;
170 }
171
172 uint64_t GetCurrentTicks() {
173 return ArchGetStopTickTime();
174 }
175
176 uint64_t GetElapsedTicks() {
177 if (!_started) {
178 return 0;
179 }
180 return ArchGetStopTickTime() - _startTicks;
181 }
182private:
183 bool _started = false;
184 uint64_t _startTicks;
185};
186
197ARCH_API
199
202ARCH_API
204
205
208#if defined(doxygen) || ARCH_USE_TSC_TIMING
209ARCH_API
211#else
212inline double ArchGetNanosecondsPerTick()
213{
214 return 1e+9 * Arch_TimingClock::period::num / Arch_TimingClock::period::den;
215}
216#endif
229#if defined(doxygen) || ARCH_USE_TSC_TIMING
230ARCH_API
231int64_t ArchTicksToNanoseconds(uint64_t nTicks);
232#else
233inline int64_t ArchTicksToNanoseconds(uint64_t nTicks)
234{
235 return static_cast<int64_t>(
236 std::llround(nTicks * ArchGetNanosecondsPerTick()));
237}
238#endif
239
242#if defined(doxygen) || ARCH_USE_TSC_TIMING
243ARCH_API
244double ArchTicksToSeconds(uint64_t nTicks);
245#else
246inline double ArchTicksToSeconds(uint64_t nTicks)
247{
248 return nTicks * ArchGetNanosecondsPerTick() / 1e+9;
249}
250#endif
251
254#if defined(doxygen) || ARCH_USE_TSC_TIMING
255ARCH_API
256uint64_t ArchSecondsToTicks(double seconds);
257#else
258inline uint64_t ArchSecondsToTicks(double seconds)
259{
260 return seconds * 1e+9 / ArchGetNanosecondsPerTick();
261}
262#endif
263
264ARCH_API
265uint64_t
266Arch_MeasureExecutionTime(uint64_t maxTicks, bool *reachedConsensus,
267 void const *m, uint64_t (*callM)(void const *, int));
268
278template <class Fn>
279uint64_t
281 Fn const &fn,
282 uint64_t maxTicks = 1e7,
283 bool *reachedConsensus = nullptr)
284{
285 auto measureN = [&fn](int nTimes) -> uint64_t {
286 ArchIntervalTimer iTimer;
287 for (int i = nTimes; i--; ) {
288 std::atomic_signal_fence(std::memory_order_seq_cst);
289 (void)fn();
290 std::atomic_signal_fence(std::memory_order_seq_cst);
291 }
292 return iTimer.GetElapsedTicks();
293 };
294
295 using MeasureNType = decltype(measureN);
296
297 return Arch_MeasureExecutionTime(
298 maxTicks, reachedConsensus,
299 static_cast<void const *>(&measureN),
300 [](void const *mN, int nTimes) {
301 return (*static_cast<MeasureNType const *>(mN))(nTimes);
302 });
303}
304
306
307PXR_NAMESPACE_CLOSE_SCOPE
308
309#endif // PXR_BASE_ARCH_TIMING_H
uint64_t ArchGetTickTime()
Return the current time in system-dependent units.
Definition: timing.h:67
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:82
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:118
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:280
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:151