aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-09-01 11:03:22 -0400
committerJack Lloyd <[email protected]>2016-09-01 11:03:22 -0400
commit35ed025b15df57dfe49fb268390a188ee901ced9 (patch)
tree7844d78c92e1f8c74121ef0da2e1a4339f0beee3
parentecc098cead587885a3b56fd7d17a4f55e73b5965 (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.cpp75
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()