#include <sys/spawn_internal.h>
#include <mach-o/dyld.h>
-#include <libkern/OSAtomic.h>
-
#include <mach/mach_time.h>
#include <mach/mach.h>
#include <mach/task.h>
#include <sys/resource.h>
+#include <stdatomic.h>
+
typedef enum wake_type { WAKE_BROADCAST_ONESEM, WAKE_BROADCAST_PERTHREAD, WAKE_CHAIN, WAKE_HOP } wake_type_t;
typedef enum my_policy_type { MY_POLICY_REALTIME, MY_POLICY_TIMESHARE, MY_POLICY_FIXEDPRI } my_policy_type_t;
#define COMPUTATION_NANOS (10000000ll) /* 10 ms */
#define TRACEWORTHY_NANOS (10000000ll) /* 10 ms */
+#define DEBUG 0
+
#if DEBUG
#define debug_log(args...) printf(args)
#else
static void selfexec_with_apptype(int argc, char *argv[]);
static void parse_args(int argc, char *argv[]);
+static __attribute__((aligned(128))) _Atomic uint32_t g_done_threads;
+static __attribute__((aligned(128))) _Atomic boolean_t g_churn_stop = FALSE;
+static __attribute__((aligned(128))) _Atomic uint64_t g_churn_stopped_at = 0;
+
/* Global variables (general) */
static uint32_t g_numcpus;
static uint32_t g_numthreads;
static struct mach_timebase_info g_mti;
static semaphore_t g_main_sem;
static uint64_t *g_thread_endtimes_abs;
-static volatile uint32_t g_done_threads;
static boolean_t g_verbose = FALSE;
static boolean_t g_do_affinity = FALSE;
static uint64_t g_starttime_abs;
static uint32_t g_priority = 0;
static uint32_t g_churn_pri = 0;
static uint32_t g_churn_count = 0;
-static uint64_t g_churn_stopped_at = 0;
-static boolean_t g_churn_stop = FALSE;
static pthread_t* g_churn_threads = NULL;
inline static void
yield(void)
{
-#if defined(__x86_64__) || defined(__i386__)
+#if defined(__arm__) || defined(__arm64__)
+ asm volatile("yield");
+#elif defined(__x86_64__) || defined(__i386__)
asm volatile("pause");
#else
#error Unrecognized architecture
}
/* This is totally racy, but only here to detect if anyone stops early */
- g_churn_stopped_at += spin_count;
+ atomic_fetch_add_explicit(&g_churn_stopped_at, spin_count, memory_order_relaxed);
return NULL;
}
static void
join_churn_threads(void)
{
- if (g_churn_stopped_at != 0)
+ if (atomic_load_explicit(&g_churn_stopped_at, memory_order_seq_cst) != 0)
printf("Warning: Some of the churn threads may have stopped early: %lld\n",
g_churn_stopped_at);
- OSMemoryBarrier();
-
- g_churn_stop = TRUE;
+ atomic_store_explicit(&g_churn_stop, TRUE, memory_order_seq_cst);
/* Rejoin churn threads */
for (uint32_t i = 0; i < g_churn_count; i++) {
debug_log("%d Leader thread go\n", i);
- assert_zero_t(my_id, g_done_threads);
+ assert_zero_t(my_id, atomic_load_explicit(&g_done_threads, memory_order_relaxed));
switch (g_waketype) {
case WAKE_BROADCAST_ONESEM:
}
}
- int32_t new = OSAtomicIncrement32((volatile int32_t *)&g_done_threads);
- (void)new;
+ uint32_t done_threads;
+ done_threads = atomic_fetch_add_explicit(&g_done_threads, 1, memory_order_relaxed) + 1;
- debug_log("Thread %p new value is %d, iteration %d\n", pthread_self(), new, i);
+ debug_log("Thread %p new value is %d, iteration %d\n", pthread_self(), done_threads, i);
if (g_drop_priority) {
/* Drop priority to BG momentarily */
if (g_do_all_spin) {
/* Everyone spins until the last thread checks in. */
- while (g_done_threads < g_numthreads) {
+ while (atomic_load_explicit(&g_done_threads, memory_order_relaxed) < g_numthreads) {
y = y + 1.5 + x;
x = sqrt(y);
}
kr = semaphore_create(mach_task_self(), &g_readysem, SYNC_POLICY_FIFO, 0);
mach_assert_zero(kr);
+ atomic_store_explicit(&g_done_threads, 0, memory_order_relaxed);
+
/* Create the threads */
- g_done_threads = 0;
for (uint32_t i = 0; i < g_numthreads; i++) {
ret = pthread_create(&threads[i], NULL, worker_thread, (void*)(uintptr_t)i);
if (ret) errc(EX_OSERR, ret, "pthread_create %d", i);
debug_log("%d Main thread reset\n", i);
- g_done_threads = 0;
- OSMemoryBarrier();
+ atomic_store_explicit(&g_done_threads, 0, memory_order_seq_cst);
g_starttime_abs = mach_absolute_time();
debug_log("%d Main thread return\n", i);
+ assert(atomic_load_explicit(&g_done_threads, memory_order_relaxed) == g_numthreads);
+
/*
* We report the worst latencies relative to start time
* and relative to the lead worker thread.