From 7f992a553df82688e68b72228f5fbb533b04b750 Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Thu, 23 May 2024 10:08:54 -0700 Subject: [PATCH] Improve compatibility with Hexagon hardware (#1785) The customization done via BENCHMARK_OS_QURT works just fine with the Hexagon simulator, but on at least some Hexagon hardware, both `qurt_timer_get_ticks()` and `std::chrono::now()` are broken and always return 0. This fixes the former by using the better-supported (and essentially identical `qurt_sysclock_get_hw_ticks()` call, and the latter by reading a 19.2MHz hardware counter (per suggestion from Qualcomm). Local testing seems to indicate these changes are just as robust under the simulator as before. --- src/timers.cc | 12 ++++++++++-- src/timers.h | 29 ++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/timers.cc b/src/timers.cc index d0821f31..7ba540b8 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -126,8 +126,12 @@ double ProcessCPUUsage() { return MakeTime(kernel_time, user_time); DiagnoseAndExit("GetProccessTimes() failed"); #elif defined(BENCHMARK_OS_QURT) + // Note that qurt_timer_get_ticks() is no longer documented as of SDK 5.3.0, + // and doesn't appear to work on at least some devices (eg Samsung S22), + // so let's use the actually-documented and apparently-equivalent + // qurt_sysclock_get_hw_ticks() call instead. return static_cast( - qurt_timer_timetick_to_us(qurt_timer_get_ticks())) * + qurt_timer_timetick_to_us(qurt_sysclock_get_hw_ticks())) * 1.0e-6; #elif defined(BENCHMARK_OS_EMSCRIPTEN) // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten. @@ -160,8 +164,12 @@ double ThreadCPUUsage() { &user_time); return MakeTime(kernel_time, user_time); #elif defined(BENCHMARK_OS_QURT) + // Note that qurt_timer_get_ticks() is no longer documented as of SDK 5.3.0, + // and doesn't appear to work on at least some devices (eg Samsung S22), + // so let's use the actually-documented and apparently-equivalent + // qurt_sysclock_get_hw_ticks() call instead. return static_cast( - qurt_timer_timetick_to_us(qurt_timer_get_ticks())) * + qurt_timer_timetick_to_us(qurt_sysclock_get_hw_ticks())) * 1.0e-6; #elif defined(BENCHMARK_OS_MACOSX) // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. diff --git a/src/timers.h b/src/timers.h index 65606ccd..690086b3 100644 --- a/src/timers.h +++ b/src/timers.h @@ -15,6 +15,29 @@ double ChildrenCPUUsage(); // Return the CPU usage of the current thread double ThreadCPUUsage(); +#if defined(BENCHMARK_OS_QURT) + +// std::chrono::now() can return 0 on some Hexagon devices; +// this reads the value of a 56-bit, 19.2MHz hardware counter +// and converts it to seconds. Unlike std::chrono, this doesn't +// return an absolute time, but since ChronoClockNow() is only used +// to compute elapsed time, this shouldn't matter. +struct QuRTClock { + typedef uint64_t rep; + typedef std::ratio<1, 19200000> period; + typedef std::chrono::duration duration; + typedef std::chrono::time_point time_point; + static const bool is_steady = false; + + static time_point now() { + unsigned long long count; + asm volatile(" %0 = c31:30 " : "=r"(count)); + return time_point(static_cast(count)); + } +}; + +#else + #if defined(HAVE_STEADY_CLOCK) template struct ChooseSteadyClock { @@ -25,10 +48,14 @@ template <> struct ChooseSteadyClock { typedef std::chrono::steady_clock type; }; +#endif // HAVE_STEADY_CLOCK + #endif struct ChooseClockType { -#if defined(HAVE_STEADY_CLOCK) +#if defined(BENCHMARK_OS_QURT) + typedef QuRTClock type; +#elif defined(HAVE_STEADY_CLOCK) typedef ChooseSteadyClock<>::type type; #else typedef std::chrono::high_resolution_clock type;