Created
March 27, 2025 16:44
-
-
Save frroossst/a2cfcd3dfd7256b9cbbe8b1802d2832a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Under high contention loads a futex should perform worse. | |
*/ | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#include <linux/futex.h> | |
#include <sys/syscall.h> | |
#include <unistd.h> | |
#include <sys/time.h> | |
#include <stdatomic.h> | |
// config | |
#define NUM_THREADS 64 | |
#define ITERATIONS 1000000 | |
#define LOW_CONTENTION_THREADS 2 | |
#define HIGH_CONTENTION_THREADS 16 | |
typedef enum { | |
SYNC_MUTEX, | |
SYNC_FUTEX | |
} SyncType; | |
// Shared benchmark state | |
typedef struct { | |
union { | |
pthread_mutex_t mutex; | |
atomic_int futex; | |
} lock; | |
int counter; | |
SyncType sync_type; | |
int thread_count; | |
} BenchmarkState; | |
// Futex wrapper functions | |
int futex_wait(atomic_int *futex, int expected) { | |
return syscall(SYS_futex, futex, FUTEX_WAIT_PRIVATE, expected, NULL, NULL, 0); | |
} | |
int futex_wake(atomic_int *futex) { | |
return syscall(SYS_futex, futex, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0); | |
} | |
// Benchmark core logic | |
void *benchmark_thread(void *arg) { | |
BenchmarkState *state = (BenchmarkState *)arg; | |
for (int i = 0; i < ITERATIONS; i++) { | |
// Locking mechanism based on sync type | |
if (state->sync_type == SYNC_MUTEX) { | |
pthread_mutex_lock(&state->lock.mutex); | |
state->counter++; | |
pthread_mutex_unlock(&state->lock.mutex); | |
} else { // FUTEX | |
while (1) { | |
int expected = 0; | |
if (atomic_compare_exchange_weak(&state->lock.futex, &expected, 1)) { | |
// Critical section | |
state->counter++; | |
// Unlock futex | |
atomic_store(&state->lock.futex, 0); | |
futex_wake(&state->lock.futex); | |
break; | |
} else { | |
// Wait on futex | |
futex_wait(&state->lock.futex, 1); | |
} | |
} | |
} | |
} | |
return NULL; | |
} | |
// Benchmark runner | |
double run_benchmark(SyncType sync_type, int thread_count) { | |
BenchmarkState state; | |
pthread_t threads[NUM_THREADS]; | |
struct timeval start, end; | |
// Initialize state | |
state.counter = 0; | |
state.sync_type = sync_type; | |
state.thread_count = thread_count; | |
if (sync_type == SYNC_MUTEX) { | |
pthread_mutex_init(&state.lock.mutex, NULL); | |
} else { | |
atomic_init(&state.lock.futex, 0); | |
} | |
// Start timing | |
gettimeofday(&start, NULL); | |
// Create threads | |
for (int i = 0; i < thread_count; i++) { | |
pthread_create(&threads[i], NULL, benchmark_thread, &state); | |
} | |
// Wait for threads to complete | |
for (int i = 0; i < thread_count; i++) { | |
pthread_join(threads[i], NULL); | |
} | |
// End timing | |
gettimeofday(&end, NULL); | |
// Calculate duration | |
double duration = (end.tv_sec - start.tv_sec) + | |
(end.tv_usec - start.tv_usec) / 1000000.0; | |
// Clean up | |
if (sync_type == SYNC_MUTEX) { | |
pthread_mutex_destroy(&state.lock.mutex); | |
} | |
return duration; | |
} | |
int main() { | |
printf("Futex vs Mutex Performance Benchmark\n"); | |
printf("-----------------------------------\n"); | |
// Low contention scenario | |
printf("Low Contention (%d threads):\n", LOW_CONTENTION_THREADS); | |
double mutex_low_time = run_benchmark(SYNC_MUTEX, LOW_CONTENTION_THREADS); | |
double futex_low_time = run_benchmark(SYNC_FUTEX, LOW_CONTENTION_THREADS); | |
printf(" Mutex Time: %.4f seconds\n", mutex_low_time); | |
printf(" Futex Time: %.4f seconds\n", futex_low_time); | |
printf(" Mutex Ops/s: %.0f\n", ITERATIONS * LOW_CONTENTION_THREADS / mutex_low_time); | |
printf(" Futex Ops/s: %.0f\n", ITERATIONS * LOW_CONTENTION_THREADS / futex_low_time); | |
// High contention scenario | |
printf("\nHigh Contention (%d threads):\n", HIGH_CONTENTION_THREADS); | |
double mutex_high_time = run_benchmark(SYNC_MUTEX, HIGH_CONTENTION_THREADS); | |
double futex_high_time = run_benchmark(SYNC_FUTEX, HIGH_CONTENTION_THREADS); | |
printf(" Mutex Time: %.4f seconds\n", mutex_high_time); | |
printf(" Futex Time: %.4f seconds\n", futex_high_time); | |
printf(" Mutex Ops/s: %.0f\n", ITERATIONS * HIGH_CONTENTION_THREADS / mutex_high_time); | |
printf(" Futex Ops/s: %.0f\n", ITERATIONS * HIGH_CONTENTION_THREADS / futex_high_time); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment