read the source · cache/04_false_sharing.c
#include "../tools/bench.h"
#include <pthread.h>
#include <stdatomic.h>
#include <stdalign.h>
#define ITERS 100000000ull
typedef struct { atomic_uint_fast64_t v; } Plain; /* 8 bytes: 8 of these share a line */
typedef struct { alignas(64) atomic_uint_fast64_t v; char pad[56]; } Padded; /* one per line */
typedef struct { atomic_uint_fast64_t *ctr; int cpu; } Arg;
static void *worker(void *p) {
Arg *a = (Arg *)p; bench_pin(a->cpu);
for (uint64_t i = 0; i < ITERS; i++) atomic_fetch_add_explicit(a->ctr, 1, memory_order_relaxed);
return NULL;
}
static double run(atomic_uint_fast64_t **ctrs, const int *cpus, int nthreads) {
pthread_t th[8]; Arg args[8];
uint64_t t0 = bench_ns();
for (int i = 0; i < nthreads; i++) { args[i].ctr = ctrs[i]; args[i].cpu = cpus[i]; pthread_create(&th[i], NULL, worker, &args[i]); }
for (int i = 0; i < nthreads; i++) pthread_join(th[i], NULL);
return (double)(bench_ns() - t0) / 1e6;
}
int main(void) {
static Plain plain[8]; static Padded padded[8]; static atomic_uint_fast64_t shared;
const int cpus[4] = {2, 4, 6, 0}; /* four different P-cores (siblings are 2-3, 4-5, 6-7, 0-1) */
atomic_uint_fast64_t *c[4];
printf("%-38s %10s %12s\n", "configuration", "ms", "ns/increment");
c[0] = &plain[0].v;
double ms1 = run(c, cpus, 1); printf("%-38s %10.1f %12.2f\n", "1 thread, own counter (baseline)", ms1, ms1 * 1e6 / ITERS);
for (int n = 2; n <= 4; n += 2) {
for (int i = 0; i < n; i++) c[i] = &plain[i].v;
double ms = run(c, cpus, n); printf("%-38s %10.1f %12.2f\n", n == 2 ? "2 threads, adjacent counters (FALSE)" : "4 threads, adjacent counters (FALSE)", ms, ms * 1e6 / ITERS);
for (int i = 0; i < n; i++) c[i] = &padded[i].v;
ms = run(c, cpus, n); printf("%-38s %10.1f %12.2f\n", n == 2 ? "2 threads, padded counters" : "4 threads, padded counters", ms, ms * 1e6 / ITERS);
for (int i = 0; i < n; i++) c[i] = &shared;
ms = run(c, cpus, n); printf("%-38s %10.1f %12.2f\n", n == 2 ? "2 threads, SAME counter (true sharing)" : "4 threads, SAME counter (true sharing)", ms, ms * 1e6 / ITERS);
}
printf("sizeof(Plain)=%zu sizeof(Padded)=%zu &plain[1]-&plain[0]=%td bytes\n", sizeof(Plain), sizeof(Padded), (char *)&plain[1] - (char *)&plain[0]);
return 0;
}