#include <assert.h>
#include <cosmo.h>
#include <pthread.h>
#include <stdatomic.h>

#define ITERATIONS 10000000l

struct {
  alignas(64) long x;
} counter[CPU_SETSIZE];

void hit(int cpu) {
  ++counter[cpu].x;
}

long count(void) {
  long r = 0;
  for (long i = 0; i < CPU_SETSIZE; ++i)
    r += counter[i].x;
  return r;
}

void *worker(void *arg) {
  int cpu;
  cpu_set_t cs;
  static atomic_int cpus;
  cpu = atomic_fetch_add_explicit(&cpus, 1, memory_order_relaxed);
  CPU_ZERO(&cs);
  CPU_SET(cpu, &cs);
  sched_setaffinity(0, sizeof(cs), &cs);
  for (long i = 0; i < ITERATIONS; ++i)
    hit(cpu);
  return 0;
}

int main(void) {
  int threads = cosmo_cpu_count();
  pthread_t th[threads];
  for (long i = 0; i < threads; ++i)
    pthread_create(&th[i], 0, worker, 0);
  for (long i = 0; i < threads; ++i)
    pthread_join(th[i], 0);
  assert(count() == threads * ITERATIONS);
}