| 1 | // This file is licensed under Apache License 2.0 |
| 2 | // Source code taken from https://github.com/google/benchmark |
| 3 | // It is highly modified |
| 4 | |
| 5 | #include "duckdb/common/cycle_counter.hpp" |
| 6 | #include "duckdb/common/chrono.hpp" |
| 7 | |
| 8 | namespace duckdb { |
| 9 | |
| 10 | inline uint64_t ChronoNow() { |
| 11 | return std::chrono::duration_cast<std::chrono::nanoseconds>( |
| 12 | d: std::chrono::time_point_cast<std::chrono::nanoseconds>(t: std::chrono::high_resolution_clock::now()) |
| 13 | .time_since_epoch()) |
| 14 | .count(); |
| 15 | } |
| 16 | |
| 17 | inline uint64_t Now() { |
| 18 | #if defined(RDTSC) |
| 19 | #if defined(__i386__) |
| 20 | uint64_t ret; |
| 21 | __asm__ volatile("rdtsc" : "=A" (ret)); |
| 22 | return ret; |
| 23 | #elif defined(__x86_64__) || defined(__amd64__) |
| 24 | uint64_t low, high; |
| 25 | __asm__ volatile("rdtsc" : "=a" (low), "=d" (high)); |
| 26 | return (high << 32) | low; |
| 27 | #elif defined(__powerpc__) || defined(__ppc__) |
| 28 | uint64_t tbl, tbu0, tbu1; |
| 29 | asm("mftbu %0" : "=r" (tbu0)); |
| 30 | asm("mftb %0" : "=r" (tbl)); |
| 31 | asm("mftbu %0" : "=r" (tbu1)); |
| 32 | tbl &= -static_cast<int64>(tbu0 == tbu1); |
| 33 | return (tbu1 << 32) | tbl; |
| 34 | #elif defined(__sparc__) |
| 35 | uint64_t tick; |
| 36 | asm(".byte 0x83, 0x41, 0x00, 0x00" ); |
| 37 | asm("mov %%g1, %0" : "=r" (tick)); |
| 38 | return tick; |
| 39 | #elif defined(__ia64__) |
| 40 | uint64_t itc; |
| 41 | asm("mov %0 = ar.itc" : "=r" (itc)); |
| 42 | return itc; |
| 43 | #elif defined(COMPILER_MSVC) && defined(_M_IX86) |
| 44 | _asm rdtsc |
| 45 | #elif defined(COMPILER_MSVC) |
| 46 | return __rdtsc(); |
| 47 | #elif defined(__aarch64__) |
| 48 | uint64_t virtual_timer_value; |
| 49 | asm volatile("mrs %0, cntvct_el0" : "=r" (virtual_timer_value)); |
| 50 | return virtual_timer_value; |
| 51 | #elif defined(__ARM_ARCH) |
| 52 | #if (__ARM_ARCH >= 6) |
| 53 | uint32_t pmccntr; |
| 54 | uint32_t pmuseren; |
| 55 | uint32_t pmcntenset; |
| 56 | asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r" (pmuseren)); |
| 57 | if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. |
| 58 | asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (pmcntenset)); |
| 59 | if (pmcntenset & 0x80000000ul) { // Is it counting? |
| 60 | asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (pmccntr)); |
| 61 | return static_cast<uint64_t>(pmccntr) * 64; // Should optimize to << 6 |
| 62 | } |
| 63 | } |
| 64 | #endif |
| 65 | return ChronoNow(); |
| 66 | #else |
| 67 | return ChronoNow(); |
| 68 | #endif |
| 69 | #else |
| 70 | return ChronoNow(); |
| 71 | #endif // defined(RDTSC) |
| 72 | } |
| 73 | uint64_t CycleCounter::Tick() const { |
| 74 | return Now(); |
| 75 | } |
| 76 | } // namespace duckdb |
| 77 | |