15dda2efdSMircea Trofin // ----------------------------------------------------------------------
25dda2efdSMircea Trofin // CycleClock
35dda2efdSMircea Trofin // A CycleClock tells you the current time in Cycles. The "time"
45dda2efdSMircea Trofin // is actually time since power-on. This is like time() but doesn't
55dda2efdSMircea Trofin // involve a system call and is much more precise.
65dda2efdSMircea Trofin //
75dda2efdSMircea Trofin // NOTE: Not all cpu/platform/kernel combinations guarantee that this
85dda2efdSMircea Trofin // clock increments at a constant rate or is synchronized across all logical
95dda2efdSMircea Trofin // cpus in a system.
105dda2efdSMircea Trofin //
115dda2efdSMircea Trofin // If you need the above guarantees, please consider using a different
125dda2efdSMircea Trofin // API. There are efforts to provide an interface which provides a millisecond
135dda2efdSMircea Trofin // granularity and implemented as a memory read. A memory read is generally
145dda2efdSMircea Trofin // cheaper than the CycleClock for many architectures.
155dda2efdSMircea Trofin //
165dda2efdSMircea Trofin // Also, in some out of order CPU implementations, the CycleClock is not
175dda2efdSMircea Trofin // serializing. So if you're trying to count at cycles granularity, your
185dda2efdSMircea Trofin // data might be inaccurate due to out of order instruction execution.
195dda2efdSMircea Trofin // ----------------------------------------------------------------------
205dda2efdSMircea Trofin
215dda2efdSMircea Trofin #ifndef BENCHMARK_CYCLECLOCK_H_
225dda2efdSMircea Trofin #define BENCHMARK_CYCLECLOCK_H_
235dda2efdSMircea Trofin
245dda2efdSMircea Trofin #include <cstdint>
255dda2efdSMircea Trofin
265dda2efdSMircea Trofin #include "benchmark/benchmark.h"
275dda2efdSMircea Trofin #include "internal_macros.h"
285dda2efdSMircea Trofin
295dda2efdSMircea Trofin #if defined(BENCHMARK_OS_MACOSX)
305dda2efdSMircea Trofin #include <mach/mach_time.h>
315dda2efdSMircea Trofin #endif
325dda2efdSMircea Trofin // For MSVC, we want to use '_asm rdtsc' when possible (since it works
335dda2efdSMircea Trofin // with even ancient MSVC compilers), and when not possible the
345dda2efdSMircea Trofin // __rdtsc intrinsic, declared in <intrin.h>. Unfortunately, in some
355dda2efdSMircea Trofin // environments, <windows.h> and <intrin.h> have conflicting
365dda2efdSMircea Trofin // declarations of some other intrinsics, breaking compilation.
375dda2efdSMircea Trofin // Therefore, we simply declare __rdtsc ourselves. See also
385dda2efdSMircea Trofin // http://connect.microsoft.com/VisualStudio/feedback/details/262047
39a5b79717SMircea Trofin #if defined(COMPILER_MSVC) && !defined(_M_IX86) && !defined(_M_ARM64) && \
40a5b79717SMircea Trofin !defined(_M_ARM64EC)
415dda2efdSMircea Trofin extern "C" uint64_t __rdtsc();
425dda2efdSMircea Trofin #pragma intrinsic(__rdtsc)
435dda2efdSMircea Trofin #endif
445dda2efdSMircea Trofin
455dda2efdSMircea Trofin #if !defined(BENCHMARK_OS_WINDOWS) || defined(BENCHMARK_OS_MINGW)
465dda2efdSMircea Trofin #include <sys/time.h>
475dda2efdSMircea Trofin #include <time.h>
485dda2efdSMircea Trofin #endif
495dda2efdSMircea Trofin
505dda2efdSMircea Trofin #ifdef BENCHMARK_OS_EMSCRIPTEN
515dda2efdSMircea Trofin #include <emscripten.h>
525dda2efdSMircea Trofin #endif
535dda2efdSMircea Trofin
545dda2efdSMircea Trofin namespace benchmark {
555dda2efdSMircea Trofin // NOTE: only i386 and x86_64 have been well tested.
565dda2efdSMircea Trofin // PPC, sparc, alpha, and ia64 are based on
575dda2efdSMircea Trofin // http://peter.kuscsik.com/wordpress/?p=14
585dda2efdSMircea Trofin // with modifications by m3b. See also
595dda2efdSMircea Trofin // https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h
605dda2efdSMircea Trofin namespace cycleclock {
615dda2efdSMircea Trofin // This should return the number of cycles since power-on. Thread-safe.
Now()625dda2efdSMircea Trofin inline BENCHMARK_ALWAYS_INLINE int64_t Now() {
635dda2efdSMircea Trofin #if defined(BENCHMARK_OS_MACOSX)
645dda2efdSMircea Trofin // this goes at the top because we need ALL Macs, regardless of
655dda2efdSMircea Trofin // architecture, to return the number of "mach time units" that
665dda2efdSMircea Trofin // have passed since startup. See sysinfo.cc where
675dda2efdSMircea Trofin // InitializeSystemInfo() sets the supposed cpu clock frequency of
685dda2efdSMircea Trofin // macs to the number of mach time units per second, not actual
695dda2efdSMircea Trofin // CPU clock frequency (which can change in the face of CPU
705dda2efdSMircea Trofin // frequency scaling). Also note that when the Mac sleeps, this
715dda2efdSMircea Trofin // counter pauses; it does not continue counting, nor does it
725dda2efdSMircea Trofin // reset to zero.
735dda2efdSMircea Trofin return mach_absolute_time();
745dda2efdSMircea Trofin #elif defined(BENCHMARK_OS_EMSCRIPTEN)
755dda2efdSMircea Trofin // this goes above x86-specific code because old versions of Emscripten
765dda2efdSMircea Trofin // define __x86_64__, although they have nothing to do with it.
775dda2efdSMircea Trofin return static_cast<int64_t>(emscripten_get_now() * 1e+6);
785dda2efdSMircea Trofin #elif defined(__i386__)
795dda2efdSMircea Trofin int64_t ret;
805dda2efdSMircea Trofin __asm__ volatile("rdtsc" : "=A"(ret));
815dda2efdSMircea Trofin return ret;
825dda2efdSMircea Trofin #elif defined(__x86_64__) || defined(__amd64__)
835dda2efdSMircea Trofin uint64_t low, high;
845dda2efdSMircea Trofin __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
855dda2efdSMircea Trofin return (high << 32) | low;
865dda2efdSMircea Trofin #elif defined(__powerpc__) || defined(__ppc__)
875dda2efdSMircea Trofin // This returns a time-base, which is not always precisely a cycle-count.
885dda2efdSMircea Trofin #if defined(__powerpc64__) || defined(__ppc64__)
895dda2efdSMircea Trofin int64_t tb;
905dda2efdSMircea Trofin asm volatile("mfspr %0, 268" : "=r"(tb));
915dda2efdSMircea Trofin return tb;
925dda2efdSMircea Trofin #else
935dda2efdSMircea Trofin uint32_t tbl, tbu0, tbu1;
945dda2efdSMircea Trofin asm volatile(
955dda2efdSMircea Trofin "mftbu %0\n"
965dda2efdSMircea Trofin "mftb %1\n"
975dda2efdSMircea Trofin "mftbu %2"
985dda2efdSMircea Trofin : "=r"(tbu0), "=r"(tbl), "=r"(tbu1));
995dda2efdSMircea Trofin tbl &= -static_cast<int32_t>(tbu0 == tbu1);
1005dda2efdSMircea Trofin // high 32 bits in tbu1; low 32 bits in tbl (tbu0 is no longer needed)
1015dda2efdSMircea Trofin return (static_cast<uint64_t>(tbu1) << 32) | tbl;
1025dda2efdSMircea Trofin #endif
1035dda2efdSMircea Trofin #elif defined(__sparc__)
1045dda2efdSMircea Trofin int64_t tick;
1055dda2efdSMircea Trofin asm(".byte 0x83, 0x41, 0x00, 0x00");
1065dda2efdSMircea Trofin asm("mov %%g1, %0" : "=r"(tick));
1075dda2efdSMircea Trofin return tick;
1085dda2efdSMircea Trofin #elif defined(__ia64__)
1095dda2efdSMircea Trofin int64_t itc;
1105dda2efdSMircea Trofin asm("mov %0 = ar.itc" : "=r"(itc));
1115dda2efdSMircea Trofin return itc;
1125dda2efdSMircea Trofin #elif defined(COMPILER_MSVC) && defined(_M_IX86)
1135dda2efdSMircea Trofin // Older MSVC compilers (like 7.x) don't seem to support the
1145dda2efdSMircea Trofin // __rdtsc intrinsic properly, so I prefer to use _asm instead
1155dda2efdSMircea Trofin // when I know it will work. Otherwise, I'll use __rdtsc and hope
1165dda2efdSMircea Trofin // the code is being compiled with a non-ancient compiler.
1175dda2efdSMircea Trofin _asm rdtsc
118a5b79717SMircea Trofin #elif defined(COMPILER_MSVC) && (defined(_M_ARM64) || defined(_M_ARM64EC))
119a290770fSMircea Trofin // See // https://docs.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
1205dda2efdSMircea Trofin // and https://reviews.llvm.org/D53115
1215dda2efdSMircea Trofin int64_t virtual_timer_value;
1225dda2efdSMircea Trofin virtual_timer_value = _ReadStatusReg(ARM64_CNTVCT);
1235dda2efdSMircea Trofin return virtual_timer_value;
1245dda2efdSMircea Trofin #elif defined(COMPILER_MSVC)
1255dda2efdSMircea Trofin return __rdtsc();
1265dda2efdSMircea Trofin #elif defined(BENCHMARK_OS_NACL)
1275dda2efdSMircea Trofin // Native Client validator on x86/x86-64 allows RDTSC instructions,
1285dda2efdSMircea Trofin // and this case is handled above. Native Client validator on ARM
1295dda2efdSMircea Trofin // rejects MRC instructions (used in the ARM-specific sequence below),
1305dda2efdSMircea Trofin // so we handle it here. Portable Native Client compiles to
1315dda2efdSMircea Trofin // architecture-agnostic bytecode, which doesn't provide any
1325dda2efdSMircea Trofin // cycle counter access mnemonics.
1335dda2efdSMircea Trofin
1345dda2efdSMircea Trofin // Native Client does not provide any API to access cycle counter.
1355dda2efdSMircea Trofin // Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday
136a5b79717SMircea Trofin // because is provides nanosecond resolution (which is noticeable at
1375dda2efdSMircea Trofin // least for PNaCl modules running on x86 Mac & Linux).
1385dda2efdSMircea Trofin // Initialize to always return 0 if clock_gettime fails.
1395dda2efdSMircea Trofin struct timespec ts = {0, 0};
1405dda2efdSMircea Trofin clock_gettime(CLOCK_MONOTONIC, &ts);
1415dda2efdSMircea Trofin return static_cast<int64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
1425dda2efdSMircea Trofin #elif defined(__aarch64__)
1435dda2efdSMircea Trofin // System timer of ARMv8 runs at a different frequency than the CPU's.
1445dda2efdSMircea Trofin // The frequency is fixed, typically in the range 1-50MHz. It can be
1455dda2efdSMircea Trofin // read at CNTFRQ special register. We assume the OS has set up
1465dda2efdSMircea Trofin // the virtual timer properly.
1475dda2efdSMircea Trofin int64_t virtual_timer_value;
1485dda2efdSMircea Trofin asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
1495dda2efdSMircea Trofin return virtual_timer_value;
1505dda2efdSMircea Trofin #elif defined(__ARM_ARCH)
1515dda2efdSMircea Trofin // V6 is the earliest arch that has a standard cyclecount
1525dda2efdSMircea Trofin // Native Client validator doesn't allow MRC instructions.
1535dda2efdSMircea Trofin #if (__ARM_ARCH >= 6)
1545dda2efdSMircea Trofin uint32_t pmccntr;
1555dda2efdSMircea Trofin uint32_t pmuseren;
1565dda2efdSMircea Trofin uint32_t pmcntenset;
1575dda2efdSMircea Trofin // Read the user mode perf monitor counter access permissions.
1585dda2efdSMircea Trofin asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
1595dda2efdSMircea Trofin if (pmuseren & 1) { // Allows reading perfmon counters for user mode code.
1605dda2efdSMircea Trofin asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
1615dda2efdSMircea Trofin if (pmcntenset & 0x80000000ul) { // Is it counting?
1625dda2efdSMircea Trofin asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
1635dda2efdSMircea Trofin // The counter is set up to count every 64th cycle
1645dda2efdSMircea Trofin return static_cast<int64_t>(pmccntr) * 64; // Should optimize to << 6
1655dda2efdSMircea Trofin }
1665dda2efdSMircea Trofin }
1675dda2efdSMircea Trofin #endif
1685dda2efdSMircea Trofin struct timeval tv;
1695dda2efdSMircea Trofin gettimeofday(&tv, nullptr);
1705dda2efdSMircea Trofin return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
1715dda2efdSMircea Trofin #elif defined(__mips__) || defined(__m68k__)
1725dda2efdSMircea Trofin // mips apparently only allows rdtsc for superusers, so we fall
1735dda2efdSMircea Trofin // back to gettimeofday. It's possible clock_gettime would be better.
1745dda2efdSMircea Trofin struct timeval tv;
1755dda2efdSMircea Trofin gettimeofday(&tv, nullptr);
1765dda2efdSMircea Trofin return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
177a5b79717SMircea Trofin #elif defined(__loongarch__) || defined(__csky__)
1785dda2efdSMircea Trofin struct timeval tv;
1795dda2efdSMircea Trofin gettimeofday(&tv, nullptr);
1805dda2efdSMircea Trofin return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
1815dda2efdSMircea Trofin #elif defined(__s390__) // Covers both s390 and s390x.
1825dda2efdSMircea Trofin // Return the CPU clock.
1835dda2efdSMircea Trofin uint64_t tsc;
184*4d34b329SFanbo Meng #if defined(BENCHMARK_OS_ZOS)
185*4d34b329SFanbo Meng // z/OS HLASM syntax.
1865dda2efdSMircea Trofin asm(" stck %0" : "=m"(tsc) : : "cc");
1875dda2efdSMircea Trofin #else
188*4d34b329SFanbo Meng // Linux on Z syntax.
1895dda2efdSMircea Trofin asm("stck %0" : "=Q"(tsc) : : "cc");
1905dda2efdSMircea Trofin #endif
1915dda2efdSMircea Trofin return tsc;
1925dda2efdSMircea Trofin #elif defined(__riscv) // RISC-V
193a5b79717SMircea Trofin // Use RDTIME (and RDTIMEH on riscv32).
194a5b79717SMircea Trofin // RDCYCLE is a privileged instruction since Linux 6.6.
1955dda2efdSMircea Trofin #if __riscv_xlen == 32
1965dda2efdSMircea Trofin uint32_t cycles_lo, cycles_hi0, cycles_hi1;
1975dda2efdSMircea Trofin // This asm also includes the PowerPC overflow handling strategy, as above.
1985dda2efdSMircea Trofin // Implemented in assembly because Clang insisted on branching.
1995dda2efdSMircea Trofin asm volatile(
200a5b79717SMircea Trofin "rdtimeh %0\n"
201a5b79717SMircea Trofin "rdtime %1\n"
202a5b79717SMircea Trofin "rdtimeh %2\n"
2035dda2efdSMircea Trofin "sub %0, %0, %2\n"
2045dda2efdSMircea Trofin "seqz %0, %0\n"
2055dda2efdSMircea Trofin "sub %0, zero, %0\n"
2065dda2efdSMircea Trofin "and %1, %1, %0\n"
2075dda2efdSMircea Trofin : "=r"(cycles_hi0), "=r"(cycles_lo), "=r"(cycles_hi1));
2085dda2efdSMircea Trofin return (static_cast<uint64_t>(cycles_hi1) << 32) | cycles_lo;
2095dda2efdSMircea Trofin #else
2105dda2efdSMircea Trofin uint64_t cycles;
211a5b79717SMircea Trofin asm volatile("rdtime %0" : "=r"(cycles));
2125dda2efdSMircea Trofin return cycles;
2135dda2efdSMircea Trofin #endif
2145dda2efdSMircea Trofin #elif defined(__e2k__) || defined(__elbrus__)
2155dda2efdSMircea Trofin struct timeval tv;
2165dda2efdSMircea Trofin gettimeofday(&tv, nullptr);
2175dda2efdSMircea Trofin return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
218a5b79717SMircea Trofin #elif defined(__hexagon__)
219a5b79717SMircea Trofin uint64_t pcycle;
220a5b79717SMircea Trofin asm volatile("%0 = C15:14" : "=r"(pcycle));
221a5b79717SMircea Trofin return static_cast<double>(pcycle);
222a5b79717SMircea Trofin #elif defined(__alpha__)
223a5b79717SMircea Trofin // Alpha has a cycle counter, the PCC register, but it is an unsigned 32-bit
224a5b79717SMircea Trofin // integer and thus wraps every ~4s, making using it for tick counts
225a5b79717SMircea Trofin // unreliable beyond this time range. The real-time clock is low-precision,
226a5b79717SMircea Trofin // roughtly ~1ms, but it is the only option that can reasonable count
227a5b79717SMircea Trofin // indefinitely.
228a5b79717SMircea Trofin struct timeval tv;
229a5b79717SMircea Trofin gettimeofday(&tv, nullptr);
230a5b79717SMircea Trofin return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
2315dda2efdSMircea Trofin #else
2325dda2efdSMircea Trofin // The soft failover to a generic implementation is automatic only for ARM.
2335dda2efdSMircea Trofin // For other platforms the developer is expected to make an attempt to create
234a5b79717SMircea Trofin // a fast implementation and use generic version if nothing better is
235a5b79717SMircea Trofin // available.
2365dda2efdSMircea Trofin #error You need to define CycleTimer for your OS and CPU
2375dda2efdSMircea Trofin #endif
2385dda2efdSMircea Trofin }
2395dda2efdSMircea Trofin } // end namespace cycleclock
2405dda2efdSMircea Trofin } // end namespace benchmark
2415dda2efdSMircea Trofin
2425dda2efdSMircea Trofin #endif // BENCHMARK_CYCLECLOCK_H_
243