From 841bfb4641f4cbad16a3aeb07fa462dcd4449cac Mon Sep 17 00:00:00 2001 From: IZUMI-Zu Date: Fri, 23 Aug 2024 00:00:12 +0800 Subject: [PATCH] RISC-V: use RDTIME for cycle timer and disable __builtin_readcyclecounter This commit backports and extends the fixes from MariaDB/server PRs #1981 and #2980 to address the RISC-V RDCYCLE privileged instruction issue. Key changes: 1. Use RDTIME instead of RDCYCLE for cycle timer on RISC-V 2. Disable __builtin_readcyclecounter() for RISC-V as LLVM generates RDCYCLE Starting with Linux 6.6 [1], RDCYCLE is a privileged instruction on RISC-V and can't be used directly from userland. There is a sysctl option to change that as a transition period, but it will eventually disappear. Use RDTIME instead, which while less accurate has the advantage of being synchronized between CPU (and thus monotonic) and of constant frequency. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cc4c07c89aada16229084eeb93895c95b7eabaa3 Backported-from: https://github.com/MariaDB/server/pull/1981 https://github.com/MariaDB/server/pull/2980 --- include/my_rdtsc.h | 26 +++++++++++++++++++++++++- mysys/my_rdtsc.c | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/my_rdtsc.h b/include/my_rdtsc.h index e8101516..880625fa 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 guaranteed to be active. + On RISC-V, we use the rdtime instruction to read from mtime register. Sadly, we have nothing for the Digital Alpha, MIPS, Motorola m68k, HP PA-RISC or other non-mainstream (or obsolete) processors. @@ -128,7 +129,7 @@ C_MODE_START */ static inline ulonglong my_timer_cycles(void) { -# if __has_builtin(__builtin_readcyclecounter) && !defined (__aarch64__) +# if __has_builtin(__builtin_readcyclecounter) && !defined(__aarch64__) && !defined(__riscv) return __builtin_readcyclecounter(); # elif defined _WIN32 || defined __i386__ || defined __x86_64__ return __rdtsc(); @@ -173,6 +174,28 @@ static inline ulonglong my_timer_cycles(void) __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result)); return result; } +#elif defined(__riscv) + /* Use RDTIME (and RDTIMEH on riscv32) */ + { +# if __riscv_xlen == 32 + ulong result_lo, result_hi0, result_hi1; + /* Implemented in assembly because Clang insisted on branching. */ + __asm __volatile__( + "rdtimeh %0\n" + "rdtime %1\n" + "rdtimeh %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__("rdtime %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(); @@ -231,6 +254,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 1503a5db..ffd81602 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 -- 2.46.0