Repository: firedancer-io/firedancer (C)

Issue:
Implement fd_tickcount for aarch64
**Problem**

fd_tickcount() falls back to CLOCK_REALTIME on aarch64.

**Suggested Fix**

Investigate other clock sources on aarch64 that satisfy the criteria for fd_tickcount (monotonically increasing, constant wrt power state, synchronous across CPUs). Maybe cntvct_el0?



Fix (patch):
diff --git a/config/extra/with-arm.mk b/config/extra/with-arm.mk
index 88c87e770bb..bb9afb9abfa 100644
--- a/config/extra/with-arm.mk
+++ b/config/extra/with-arm.mk
@@ -37,3 +37,6 @@ include config/extra/with-rocksdb.mk
 endif
 
 FD_ARCH_SUPPORTS_SANDBOX:=1
+
+CPPFLAGS+=-DFD_HAS_ARM=1
+FD_HAS_ARM:=1
diff --git a/src/app/firedancer/commands/shred_version.c b/src/app/firedancer/commands/shred_version.c
index dc760664ffb..ce8d7428667 100644
--- a/src/app/firedancer/commands/shred_version.c
+++ b/src/app/firedancer/commands/shred_version.c
@@ -4,6 +4,7 @@
 #include "../../../disco/topo/fd_topo.h"
 #include "../../../discof/ipecho/fd_ipecho_client.h"
 
+#include <stdlib.h>
 #include <unistd.h>
 
 void
diff --git a/src/util/clock/fd_clock.c b/src/util/clock/fd_clock.c
index 816b670f0b6..38df1fbe217 100644
--- a/src/util/clock/fd_clock.c
+++ b/src/util/clock/fd_clock.c
@@ -355,11 +355,11 @@ fd_clock_joint_read( fd_clock_func_t clock_x, void const * args_x,
   x[ FD_CLOCK_JOINT_READ_CNT ] = clock_x( args_x );
 
   ulong best_idx = 0UL;
-  long  best_dx  = x[1] - x[0]; if( FD_UNLIKELY( best_dx<=0L ) ) return FD_CLOCK_ERR_X;
+  long  best_dx  = x[1] - x[0]; if( FD_UNLIKELY( best_dx<0L ) ) return FD_CLOCK_ERR_X;
 
   for( ulong idx=1UL; idx<FD_CLOCK_JOINT_READ_CNT; idx++ ) {
-    long dy  = y[ idx ] - y[ idx-1UL ]; if( FD_UNLIKELY( dy<=0L ) ) return FD_CLOCK_ERR_Y;
-    long dx  = x[ idx+1UL ] - x[ idx ]; if( FD_UNLIKELY( dx<=0L ) ) return FD_CLOCK_ERR_X;
+    long dy  = y[ idx ] - y[ idx-1UL ]; if( FD_UNLIKELY( dy<0L ) ) return FD_CLOCK_ERR_Y;
+    long dx  = x[ idx+1UL ] - x[ idx ]; if( FD_UNLIKELY( dx<0L ) ) return FD_CLOCK_ERR_X;
     best_idx = fd_ulong_if( best_dx<dx, best_idx, idx );
     best_dx  = fd_long_min( best_dx, dx );
   }
diff --git a/src/util/fd_util_base.h b/src/util/fd_util_base.h
index 45456bebe75..67d4890cc60 100644
--- a/src/util/fd_util_base.h
+++ b/src/util/fd_util_base.h
@@ -181,6 +181,14 @@
 #define FD_HAS_AESNI 0
 #endif
 
+/* FD_HAS_ARM:  If the build target supports armv8-a specific features
+   and can benefit from aarch64 specific optimizations, define
+   FD_HAS_ARM. */
+
+#ifndef FD_HAS_ARM
+#define FD_HAS_ARM 0
+#endif
+
 /* FD_HAS_LZ4 indicates that the target supports LZ4 compression.
    Roughly, does "#include <lz4.h>" and the APIs therein work? */
 
@@ -1245,6 +1253,8 @@ fd_hash_memcpy( ulong                    seed,
 #ifndef FD_TICKCOUNT_STYLE
 #if FD_HAS_X86 /* Use RDTSC */
 #define FD_TICKCOUNT_STYLE 1
+#elif FD_HAS_ARM /* Use CNTVCT_EL0 */
+#define FD_TICKCOUNT_STYLE 2
 #else /* Use portable fallback */
 #define FD_TICKCOUNT_STYLE 0
 #endif
@@ -1290,6 +1300,23 @@ fd_hash_memcpy( ulong                    seed,
 
 #define fd_tickcount() ((long)__builtin_ia32_rdtsc())
 
+#elif FD_TICKCOUNT_STYLE==2 /* armv8 (fast) */
+
+/* fd_tickcount (ARM): https://developer.arm.com/documentation/ddi0601/2021-12/AArch64-Registers/CNTVCT-EL0--Counter-timer-Virtual-Count-register
+   Approx 24 MHz on Apple M1. */
+
+static inline long
+fd_tickcount( void ) {
+  /* consider using 'isb' */
+  ulong value;
+  __asm__ __volatile__ (
+    "isb\n"
+    "mrs %0, cntvct_el0\n"
+    "nop"
+    : "=r" (value) );
+  return (long)value;
+}
+
 #else
 #error "Unknown FD_TICKCOUNT_STYLE"
 #endif