diff options
author | Jack Lloyd <[email protected]> | 2016-09-01 11:03:22 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-09-01 11:03:22 -0400 |
commit | 35ed025b15df57dfe49fb268390a188ee901ced9 (patch) | |
tree | 7844d78c92e1f8c74121ef0da2e1a4339f0beee3 | |
parent | ecc098cead587885a3b56fd7d17a4f55e73b5965 (diff) |
get_processor_timestamp should never return 0 if it can help it.
For example it used to return 0 on Linux/ARM...
If no QPC or asm version, use clock_gettime if available, or else
std::chrono::high_resolution_clock as a fallback.
-rw-r--r-- | src/lib/utils/os_utils.cpp | 75 |
1 files changed, 59 insertions, 16 deletions
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp index eab509984..2f17da952 100644 --- a/src/lib/utils/os_utils.cpp +++ b/src/lib/utils/os_utils.cpp @@ -40,49 +40,92 @@ uint32_t get_process_id() uint64_t get_processor_timestamp() { - uint64_t rtc = 0; - #if defined(BOTAN_TARGET_OS_HAS_QUERY_PERF_COUNTER) LARGE_INTEGER tv; ::QueryPerformanceCounter(&tv); - rtc = tv.QuadPart; -#endif - -#if defined(BOTAN_USE_GCC_INLINE_ASM) + return tv.QuadPart; -#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) if(CPUID::has_rdtsc()) // not available on all x86 CPUs { uint32_t rtc_low = 0, rtc_high = 0; asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low)); - rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low; + return (static_cast<u64bit>(rtc_high) << 32) | rtc_low; } -#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) uint32_t rtc_low = 0, rtc_high = 0; asm volatile("mftbu %0; mftb %1" : "=r" (rtc_high), "=r" (rtc_low)); - rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low; + return (static_cast<u64bit>(rtc_high) << 32) | rtc_low; -#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ALPHA) + uint64_t rtc = 0; asm volatile("rpcc %0" : "=r" (rtc)); + return rtc; -#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) // OpenBSD does not trap access to the %tick register +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) + uint64_t rtc = 0; asm volatile("rd %%tick, %0" : "=r" (rtc)); + return rtc; -#elif defined(BOTAN_TARGET_ARCH_IS_IA64) +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_IA64) + uint64_t rtc = 0; asm volatile("mov %0=ar.itc" : "=r" (rtc)); + return rtc; -#elif defined(BOTAN_TARGET_ARCH_IS_S390X) +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_S390X) + uint64_t rtc = 0; asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc"); + return rtc; -#elif defined(BOTAN_TARGET_ARCH_IS_HPPA) +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_HPPA) + uint64_t rtc = 0; asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only? + return rtc; #endif + /* + If we got here either we either don't have an asm instruction + above, or (for x86) RDTSC is not available at runtime. Try some + clock_gettimes and return the first one that works, or otherwise + fall back to std::chrono. + */ + +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + + // The ordering here is somewhat arbitrary... + const clockid_t clock_types[] = { +#if defined(CLOCK_MONOTONIC_HR) + CLOCK_MONOTONIC_HR, +#endif +#if defined(CLOCK_MONOTONIC_RAW) + CLOCK_MONOTONIC_RAW, #endif +#if defined(CLOCK_MONOTONIC) + CLOCK_MONOTONIC, +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) + CLOCK_PROCESS_CPUTIME_ID, +#endif +#if defined(CLOCK_THREAD_CPUTIME_ID) + CLOCK_THREAD_CPUTIME_ID, +#endif + }; - return rtc; + for(clockid_t clock : clock_types) + { + struct timespec ts; + if(::clock_gettime(clock, &ts) == 0) + { + return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec); + } + } +#endif + + // Plain C++11 fallback + auto now = std::chrono::high_resolution_clock::now().time_since_epoch(); + return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count(); } uint64_t get_system_timestamp_ns() |