Loading...
Searching...
No Matches
timing.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_BASE_ARCH_TIMING_H
25#define PXR_BASE_ARCH_TIMING_H
26
30
31#include "pxr/pxr.h"
32#include "pxr/base/arch/api.h"
33#include "pxr/base/arch/defines.h"
35
38
39#if defined(ARCH_OS_LINUX) && defined(ARCH_CPU_INTEL)
40#include <x86intrin.h>
41#elif defined(ARCH_OS_DARWIN)
42#include <mach/mach_time.h>
43#elif defined(ARCH_OS_WINDOWS)
44#include <intrin.h>
45#endif
46
47#include <algorithm>
48#include <atomic>
49#include <iterator>
50#include <numeric>
51
52PXR_NAMESPACE_OPEN_SCOPE
53
61inline uint64_t
63{
64#if defined(ARCH_OS_DARWIN)
65 // On Darwin we'll use mach_absolute_time().
66 return mach_absolute_time();
67#elif defined(ARCH_CPU_INTEL)
68 // On Intel we'll use the rdtsc instruction.
69 return __rdtsc();
70#elif defined (ARCH_CPU_ARM)
71 uint64_t result;
72 __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
73 return result;
74#else
75#error Unknown architecture.
76#endif
77}
78
79
84inline uint64_t
86{
87 uint64_t t;
88#if defined (ARCH_OS_DARWIN)
89 return ArchGetTickTime();
90#elif defined (ARCH_CPU_ARM)
91 std::atomic_signal_fence(std::memory_order_seq_cst);
92 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
93 std::atomic_signal_fence(std::memory_order_seq_cst);
94#elif defined (ARCH_COMPILER_MSVC)
95 _mm_lfence();
96 std::atomic_signal_fence(std::memory_order_seq_cst);
97 t = __rdtsc();
98 _mm_lfence();
99 std::atomic_signal_fence(std::memory_order_seq_cst);
100#elif defined(ARCH_CPU_INTEL) && \
101 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
102 // Prevent reorders by the compiler.
103 std::atomic_signal_fence(std::memory_order_seq_cst);
104 asm volatile(
105 "lfence\n\t"
106 "rdtsc\n\t"
107 "shl $32, %%rdx\n\t"
108 "or %%rdx, %0\n\t"
109 "lfence"
110 : "=a"(t)
111 :
112 // rdtsc writes rdx
113 // shl modifies cc flags
114 : "rdx", "cc");
115#else
116#error "Unsupported architecture."
117#endif
118 return t;
119}
120
125inline uint64_t
127{
128 uint64_t t;
129#if defined (ARCH_OS_DARWIN)
130 return ArchGetTickTime();
131#elif defined (ARCH_CPU_ARM)
132 std::atomic_signal_fence(std::memory_order_seq_cst);
133 asm volatile("mrs %0, cntvct_el0" : "=r"(t));
134 std::atomic_signal_fence(std::memory_order_seq_cst);
135#elif defined (ARCH_COMPILER_MSVC)
136 std::atomic_signal_fence(std::memory_order_seq_cst);
137 unsigned aux;
138 t = __rdtscp(&aux);
139 _mm_lfence();
140 std::atomic_signal_fence(std::memory_order_seq_cst);
141#elif defined(ARCH_CPU_INTEL) && \
142 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))
143 std::atomic_signal_fence(std::memory_order_seq_cst);
144 asm volatile(
145 "rdtscp\n\t"
146 "shl $32, %%rdx\n\t"
147 "or %%rdx, %0\n\t"
148 "lfence"
149 : "=a"(t)
150 :
151 // rdtscp writes rcx & rdx
152 // shl modifies cc flags
153 : "rcx", "rdx", "cc");
154#else
155#error "Unsupported architecture."
156#endif
157 return t;
158}
159
160#if defined (doxygen) || \
161 (!defined(ARCH_OS_DARWIN) && defined(ARCH_CPU_INTEL) && \
162 (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC)))
163
167{
169 explicit ArchIntervalTimer(bool start=true)
170 : _started(start) {
171 if (_started) {
172 Start();
173 }
174 }
175
177 void Start() {
178 _started = true;
179 std::atomic_signal_fence(std::memory_order_seq_cst);
180 asm volatile(
181 "lfence\n\t"
182 "rdtsc\n\t"
183 "lfence"
184 : "=a"(_startLow), "=d"(_startHigh) :: );
185 }
186
188 bool IsStarted() const {
189 return _started;
190 }
191
193 uint64_t GetStartTicks() const {
194 return (uint64_t(_startHigh) << 32) + _startLow;
195 }
196
198 uint64_t GetCurrentTicks() {
199 return ArchGetStopTickTime();
200 }
201
204 uint64_t GetElapsedTicks() {
205 if (!_started) {
206 return 0;
207 }
208 uint32_t stopLow, stopHigh;
209 std::atomic_signal_fence(std::memory_order_seq_cst);
210 asm volatile(
211 "rdtscp\n\t"
212 "lfence"
213 : "=a"(stopLow), "=d"(stopHigh)
214 :
215 // rdtscp writes rcx
216 : "rcx");
217 return ((uint64_t(stopHigh) << 32) + stopLow) -
218 ((uint64_t(_startHigh) << 32) + _startLow);
219 }
220private:
221 bool _started = false;
222 uint32_t _startLow = 0, _startHigh = 0;
223};
224
225#else
226
228{
229 explicit ArchIntervalTimer(bool start=true)
230 : _started(start) {
231 if (_started) {
232 _startTicks = ArchGetStartTickTime();
233 }
234 }
235
236 void Start() {
237 _started = true;
238 _startTicks = ArchGetStartTickTime();
239 }
240
241 bool IsStarted() const {
242 return _started;
243 }
244
245 uint64_t GetStartTicks() const {
246 return _startTicks;
247 }
248
249 uint64_t GetCurrentTicks() {
250 return ArchGetStopTickTime();
251 }
252
253 uint64_t GetElapsedTicks() {
254 if (!_started) {
255 return 0;
256 }
257 return ArchGetStopTickTime() - _startTicks;
258 }
259private:
260 bool _started = false;
261 uint64_t _startTicks;
262};
263
264#endif
265
276ARCH_API
278
281ARCH_API
283
284
297ARCH_API
298int64_t ArchTicksToNanoseconds(uint64_t nTicks);
299
302ARCH_API
303double ArchTicksToSeconds(uint64_t nTicks);
304
307ARCH_API
308uint64_t ArchSecondsToTicks(double seconds);
309
312ARCH_API
314
315ARCH_API
316uint64_t
317Arch_MeasureExecutionTime(uint64_t maxTicks, bool *reachedConsensus,
318 void const *m, uint64_t (*callM)(void const *, int));
319
329template <class Fn>
330uint64_t
332 Fn const &fn,
333 uint64_t maxTicks = 1e7,
334 bool *reachedConsensus = nullptr)
335{
336 auto measureN = [&fn](int nTimes) -> uint64_t {
337 ArchIntervalTimer iTimer;
338 for (int i = nTimes; i--; ) {
339 std::atomic_signal_fence(std::memory_order_seq_cst);
340 (void)fn();
341 std::atomic_signal_fence(std::memory_order_seq_cst);
342 }
343 return iTimer.GetElapsedTicks();
344 };
345
346 using MeasureNType = decltype(measureN);
347
348 return Arch_MeasureExecutionTime(
349 maxTicks, reachedConsensus,
350 static_cast<void const *>(&measureN),
351 [](void const *mN, int nTimes) {
352 return (*static_cast<MeasureNType const *>(mN))(nTimes);
353 });
354}
355
357
358PXR_NAMESPACE_CLOSE_SCOPE
359
360#endif // PXR_BASE_ARCH_TIMING_H
uint64_t ArchGetTickTime()
Return the current time in system-dependent units.
Definition: timing.h:62
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:85
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:126
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:331
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:167
uint64_t GetCurrentTicks()
Read and return the current time.
Definition: timing.h:198
void Start()
Start the timer, or reset the start time if it has already been started.
Definition: timing.h:177
uint64_t GetStartTicks() const
Return this timer's start time, or 0 if it hasn't been started.
Definition: timing.h:193
uint64_t GetElapsedTicks()
Read the current time and return the difference between it and the start time.
Definition: timing.h:204
ArchIntervalTimer(bool start=true)
Construct a timer and start timing if start is true.
Definition: timing.h:169
bool IsStarted() const
Return true if this timer is started.
Definition: timing.h:188