From c0fd8fd89ad3d1b3aed4ed41feddb03f946d66c1 Mon Sep 17 00:00:00 2001 From: alexfanqi Date: Tue, 4 Jan 2022 13:59:59 +1100 Subject: [PATCH] MDEV-27429: Support RISC-V cycle timer Adapted from https://github.com/google/benchmark/pull/833 authored by Sam Elliot at lowRISC. This requires the RISCV kernel to set the CY bit of the mcountern register which is done on Linux, but documenting here in case another OS hits a SIGILL here. When CY bit of the mcounteren register is unset, reading the cycle register will cause illegal instruction exception in the next privilege level ( user mode or supervisor mode ). See the privileged isa manual section 3.1.11 in https://github.com/riscv/riscv-isa-manual/releases/latest --- include/my_rdtsc.h | 24 ++++++++++++++++++++++++ mysys/my_rdtsc.c | 2 ++ 2 files changed, 26 insertions(+) diff --git a/include/my_rdtsc.h b/include/my_rdtsc.h index 5a6f4a8701240..10b695673366a 100644 --- a/include/my_rdtsc.h +++ b/include/my_rdtsc.h @@ -91,6 +91,7 @@ C_MODE_START On AARCH64, we use the generic timer base register. We override clang implementation for aarch64 as it access a PMU register which is not guarenteed to be active. + On RISC-V, we use the rdcycle instruction to read from mcycle register. Sadly, we have nothing for the Digital Alpha, MIPS, Motorola m68k, HP PA-RISC or other non-mainstream (or obsolete) processors. @@ -175,6 +176,28 @@ static inline ulonglong my_timer_cycles(void) __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result)); return result; } +#elif defined(__riscv) + /* Use RDCYCLE (and RDCYCLEH on riscv32) */ + { +# if __riscv_xlen == 32 + ulong result_lo, result_hi0, result_hi1; + /* Implemented in assembly because Clang insisted on branching. */ + __asm __volatile__( + "rdcycleh %0\n" + "rdcycle %1\n" + "rdcycleh %2\n" + "sub %0, %0, %2\n" + "seqz %0, %0\n" + "sub %0, zero, %0\n" + "and %1, %1, %0\n" + : "=r"(result_hi0), "=r"(result_lo), "=r"(result_hi1)); + return (static_cast(result_hi1) << 32) | result_lo; +# else + ulonglong result; + __asm __volatile__("rdcycle %0" : "=r"(result)); + return result; + } +# endif #elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) /* gethrtime may appear as either cycle or nanosecond counter */ return (ulonglong) gethrtime(); @@ -233,6 +256,7 @@ C_MODE_END #define MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME 26 #define MY_TIMER_ROUTINE_ASM_S390 28 #define MY_TIMER_ROUTINE_AARCH64 29 +#define MY_TIMER_ROUTINE_RISCV 30 #endif diff --git a/mysys/my_rdtsc.c b/mysys/my_rdtsc.c index 1503a5db44259..ffd816024e53d 100644 --- a/mysys/my_rdtsc.c +++ b/mysys/my_rdtsc.c @@ -384,6 +384,8 @@ void my_timer_init(MY_TIMER_INFO *mti) mti->cycles.routine= MY_TIMER_ROUTINE_ASM_S390; #elif defined(__GNUC__) && defined (__aarch64__) mti->cycles.routine= MY_TIMER_ROUTINE_AARCH64; +#elif defined(__GNUC__) && defined (__riscv) + mti->cycles.routine= MY_TIMER_ROUTINE_RISCV; #elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) mti->cycles.routine= MY_TIMER_ROUTINE_GETHRTIME; #else