// File: /workspace/github_c_makefile_star2_O2/google[P]multichase/fairness.c
// Function: main
int main(int argc, char **argv) {
  int c;
  int sweep_max = 1;
  size_t time_slice = 500000;
  char sep = ' ';
  size_t sample_size = 6;

  delay_mask = 0;
  while ((c = getopt(argc, argv, "d:n:s:t:S:")) != -1) {
    switch (c) {
      case 'd':
        delay_mask = strtoul(optarg, 0, 0);
        break;
      case 'n':
        sample_size =  strtof(optarg, 0);
        break;
      case 's':
        sweep_max = strtoul(optarg, 0, 0);
        break;
      case 't':
        time_slice = strtof(optarg, 0) * 1000000;
        break;
      case 'S':
        sep = *optarg;
        break;
      default:
        goto usage;
    }
  }

  if (argc - optind != 0) {
  usage:
    fprintf(
        stderr,
        "usage: %s \n"
        " [-d delay_mask]\n"
        " [-n sample_nr]\n"
        " [-s sweep_max]\n"
        " [-t time]\n"
        "By default runs one thread on each cpu, use taskset(1) to "
        "restrict operation to fewer cpus/threads.\n"
        "The optional delay_mask specifies a mask of cpus on which to delay "
        "the startup.\n"
        "The optional sample_nr determines the number of samples taken for "
        "each test point.\n"
        "The optional sweep_max causes testing across multiple different "
        "cache lines.\n"
        "The optional time determines how often to poll results (float in "
        "seconds).\n",
        argv[0]);
    exit(1);
  }

  setvbuf(stdout, NULL, _IONBF, BUFSIZ);

  // find the active cpus
  cpu_set_t cpus;
  if (sched_getaffinity(getpid(), sizeof(cpus), &cpus)) {
    perror("sched_getaffinity");
    exit(1);
  }

  // could do this more efficiently, but whatever
  size_t nr_threads = 0;
  int i;
  for (i = 0; i < CPU_SETSIZE; ++i) {
    if (CPU_ISSET(i, &cpus)) {
      ++nr_threads;
    }
  }

  per_thread_t *thread_args = calloc(nr_threads, sizeof(*thread_args));
  nr_to_startup = nr_threads + 1;
  size_t u;
  i = 0;
  for (u = 0; u < nr_threads; ++u) {
    while (!CPU_ISSET(i, &cpus)) {
      ++i;
    }
    thread_args[u].x.cpu = i;
    ++i;
    thread_args[u].x.count = 0;
    pthread_t dummy;
    if (pthread_create(&dummy, NULL, worker, &thread_args[u])) {
      perror("pthread_create");
      exit(1);
    }
  }

  wait_for_startup();

  atomic_t *samples = calloc(nr_threads, sizeof(*samples));

  printf(
      "results are avg latency per locked increment in ns, one column per "
      "thread\n");
  char *fmt, *tail = "";
  if (sep == ',') {
    printf("relaxed,sweep");
    fmt = ",cpu-%u";
    tail = ",avg,stdev,min,max";
  } else {
    fmt = "%6u  ";
    printf("cpu:");
  }
  for (u = 0; u < nr_threads; ++u) {
    printf(fmt, thread_args[u].x.cpu);
  }
  printf("%s\n", tail);
  global_counter.sweep_id = 0;
  for (relaxed = 0; relaxed < 2; ++relaxed) {
    if (sep != ',') printf(relaxed ? "relaxed:\n" : "unrelaxed:\n");
    for (int sweep = 0; sweep < sweep_max; sweep++) {
      global_counter.sweep_id = sweep;
      uint64_t last_stamp = now_nsec();
      size_t sample_nr;
      // The first sample is thrown out, so increment sample_size by 1 to get
      // the requested number of samples.
      for (sample_nr = 0; sample_nr < sample_size + 1; ++sample_nr) {
        double min = 1.0 / 0., max = 0.;
        usleep(time_slice);
        for (u = 0; u < nr_threads; ++u) {
          samples[u] = __sync_lock_test_and_set(&thread_args[u].x.count, 0);
        }
        uint64_t stamp = now_nsec();
        int64_t time_delta = stamp - last_stamp;
        last_stamp = stamp;

        // throw away the first sample to avoid race issues at startup / mode
        // switch
        if (sample_nr == 0) continue;
        if (sep == ',')
          printf("%d,%p", relaxed,
                 &(global_counter.x[global_counter.sweep_id].count));

        if (sep == ',') {
          fmt = ",%.1f";
        } else {
          fmt = "  %6.1f";
          printf("  ");
        }
        double sum = 0.;
        double sum_squared = 0.;
        for (u = 0; u < nr_threads; ++u) {
          double s = time_delta / (double)samples[u];
          printf(fmt, s);
          min = min < s ? min : s;
          max = max > s ? max : s;
          sum += s;
          sum_squared += s * s;
        }
        if (sep == ',') {
          fmt = ",%.1f,%.1f,%.1f,%.1f\n";
        } else {
          fmt = " : avg %6.1f  sdev %6.1f  min %6.1f  max %6.1f\n";
        }
        printf(fmt, sum / nr_threads,
               sqrt((sum_squared - sum * sum / nr_threads) / (nr_threads - 1)),
               min, max);
        fflush(stdout);
      }
    }
  }
  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
movq %rsi, %rbx
movl %edi, %ebp
andq $0x0, 0xebb6a(%rip)     # 0x4ed310
pushq $0x1
popq %rax
movq %rax, 0x10(%rsp)
movl $0x7a120, %eax          # imm = 0x7A120
movq %rax, 0x30(%rsp)
movb $0x20, 0xf(%rsp)
pushq $0x6
popq %rax
movq %rax, 0x20(%rsp)
leaq 0xb5874(%rip), %r15     # 0x4b7040
movq $0x4f6360, %r14         # imm = 0x4F6360
movl %ebp, %edi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x463530
cmpl $0x64, %eax
jne 0x4017fa
movq (%r14), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x40b790
movq %rax, 0xebb18(%rip)     # 0x4ed310
jmp 0x4017d3
cmpl $-0x1, %eax
je 0x4018b1
cmpl $0x53, %eax
je 0x40185a
cmpl $0x6e, %eax
je 0x401868
cmpl $0x73, %eax
je 0x40189b
cmpl $0x74, %eax
jne 0x401d07
movq (%r14), %rdi
xorl %esi, %esi
callq 0x40bca0
mulss 0xb57d3(%rip), %xmm0    # 0x4b7004
cvttss2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subss 0xb57c3(%rip), %xmm0    # 0x4b7008
cvttss2si %xmm0, %rdx
andq %rcx, %rdx
orq %rax, %rdx
movq %rdx, 0x30(%rsp)
jmp 0x4017d3
movq (%r14), %rax
movb (%rax), %al
movb %al, 0xf(%rsp)
jmp 0x4017d3
movq (%r14), %rdi
xorl %esi, %esi
callq 0x40bca0
cvttss2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subss 0xb5782(%rip), %xmm0    # 0x4b7008
cvttss2si %xmm0, %rdx
andq %rcx, %rdx
orq %rax, %rdx
movq %rdx, 0x20(%rsp)
jmp 0x4017d3
movq (%r14), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x40b790
movq %rax, 0x10(%rsp)
jmp 0x4017d3
movq $0x4ec0a0, %rax         # imm = 0x4EC0A0
cmpl %ebp, (%rax)
jne 0x401d07
movq $0x4eb710, %rax         # imm = 0x4EB710
movq (%rax), %rdi
pushq $0x2
popq %rdx
movl $0x2000, %ecx           # imm = 0x2000
xorl %esi, %esi
callq 0x417ab0
callq 0x461e60
leaq 0x98(%rsp), %rdx
movl $0x80, %esi
movl %eax, %edi
callq 0x463730
testl %eax, %eax
jne 0x401d38
xorl %eax, %eax
xorl %r15d, %r15d
cmpq $0x400, %rax            # imm = 0x400
je 0x401923
movq %rax, %rcx
shrq $0x6, %rcx
movq 0x98(%rsp,%rcx,8), %rcx
btq %rax, %rcx
adcq $0x0, %r15
incq %rax
jmp 0x4018ff
movl $0x400, %esi            # imm = 0x400
movq %r15, %rdi
callq 0x42bb20
movq %rax, 0x18(%rsp)
leaq 0x1(%r15), %rax
movq %rax, 0xeb9d8(%rip)     # 0x4ed318
xorl %r12d, %r12d
leaq 0x3f7(%rip), %rbx       # 0x401d41
leaq 0x90(%rsp), %r14
xorl %r13d, %r13d
cmpq %r15, %r13
jne 0x40195f
jmp 0x4019b2
incl %r12d
cmpl $0x3ff, %r12d           # imm = 0x3FF
ja 0x40195c
movl %r12d, %eax
shrl $0x6, %eax
movq 0x98(%rsp,%rax,8), %rax
btq %r12, %rax
jae 0x40195c
movq %r13, %rax
shlq $0xa, %rax
movq 0x18(%rsp), %rdx
leaq (%rdx,%rax), %rcx
movl %r12d, 0x4(%rdx,%rax)
andl $0x0, (%rdx,%rax)
movq %r14, %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0x421bf0
testl %eax, %eax
jne 0x401d24
incl %r12d
incq %r13
jmp 0x401955
callq 0x4020a3
pushq $0x4
popq %rsi
movq %r15, %rdi
callq 0x42bb20
movq %rax, %r13
leaq 0xb5933(%rip), %rdi     # 0x4b72ff
callq 0x417910
cmpb $0x2c, 0xf(%rsp)
leaq 0xb5876(%rip), %rax     # 0x4b7253
leaq 0xb589e(%rip), %rdi     # 0x4b7282
cmoveq %rax, %rdi
leaq 0xb5872(%rip), %rax     # 0x4b7261
leaq 0xb5886(%rip), %rbx     # 0x4b727c
cmoveq %rax, %rbx
leaq 0xb5868(%rip), %rax     # 0x4b7269
leaq 0xd17ad(%rip), %r14     # 0x4d31b5
cmoveq %rax, %r14
xorl %eax, %eax
callq 0x4108f0
movq 0x18(%rsp), %r12
addq $0x4, %r12
movq %r15, %rbp
subq $0x1, %rbp
jb 0x401a3c
movl (%r12), %esi
movq %rbx, %rdi
xorl %eax, %eax
callq 0x4108f0
addq $0x400, %r12            # imm = 0x400
jmp 0x401a1f
movq %r14, %rdi
callq 0x417910
andl $0x0, 0xef8d5(%rip)     # 0x4f1320
incq 0x20(%rsp)
xorl %eax, %eax
cmpb $0x2c, 0xf(%rsp)
leaq 0xb5849(%rip), %rcx     # 0x4b72a7
leaq 0xb5858(%rip), %rdx     # 0x4b72bd
cmoveq %rcx, %rdx
movq %rdx, 0x50(%rsp)
movl %eax, 0xef8b0(%rip)     # 0x4f1324
movq %r15, %xmm0
movq 0xb558f(%rip), %xmm1    # 0x4b7010
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0xb5593(%rip), %xmm2    # 0x4b7020
subpd %xmm2, %xmm0
movapd %xmm0, %xmm3
unpckhpd %xmm0, %xmm3            # xmm3 = xmm3[1],xmm0[1]
addsd %xmm0, %xmm3
movapd %xmm3, 0x70(%rsp)
leaq -0x1(%r15), %rcx
movq %rcx, %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
subpd %xmm2, %xmm0
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movapd %xmm1, 0x80(%rsp)
movq 0x10(%rsp), %rcx
testl %ecx, %ecx
cmovlel %eax, %ecx
movq %rcx, 0x10(%rsp)
movl 0xef846(%rip), %eax     # 0x4f1324
cmpl $0x1, %eax
jg 0x401cf3
cmpb $0x2c, 0xf(%rsp)
je 0x401b0e
cmpl $0x0, 0xef82f(%rip)     # 0x4f1324
leaq 0xb578d(%rip), %rdi     # 0x4b7289
leaq 0xb5784(%rip), %rax     # 0x4b7287
cmoveq %rax, %rdi
xorl %eax, %eax
callq 0x4108f0
xorl %eax, %eax
cmpl 0x10(%rsp), %eax
je 0x401ce8
movl %eax, 0x2c(%rsp)
movl %eax, 0xef7fc(%rip)     # 0x4f1320
callq 0x4020e7
movq %rax, %r14
xorl %r12d, %r12d
cmpq 0x20(%rsp), %r12
je 0x401cdd
movq 0x30(%rsp), %rdi
callq 0x464870
movq 0x18(%rsp), %rax
xorl %ecx, %ecx
cmpq %rcx, %r15
je 0x401b64
xorl %edx, %edx
xchgl %edx, (%rax)
movl %edx, (%r13,%rcx,4)
incq %rcx
addq $0x400, %rax            # imm = 0x400
jmp 0x401b4b
callq 0x4020e7
movq %rax, %rbx
testq %r12, %r12
je 0x401cd2
cmpb $0x2c, 0xf(%rsp)
jne 0x401bae
movl 0xef7a2(%rip), %esi     # 0x4f1324
movslq 0xef797(%rip), %rdx     # 0x4f1320
shlq $0x6, %rdx
leaq 0xeb78c(%rip), %rax     # 0x4ed320
addq %rax, %rdx
leaq 0xb56f5(%rip), %rdi     # 0x4b7293
xorl %eax, %eax
callq 0x4108f0
leaq 0xb56ed(%rip), %rbp     # 0x4b7299
jmp 0x401bc3
leaq 0xb56ca(%rip), %rdi     # 0x4b727f
xorl %eax, %eax
callq 0x4108f0
leaq 0xb56dc(%rip), %rbp     # 0x4b729f
movq %rbx, %rax
subq %r14, %rax
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x58(%rsp)
xorpd %xmm3, %xmm3
xorl %r14d, %r14d
movsd 0xb544d(%rip), %xmm2    # 0x4b7030
xorpd %xmm4, %xmm4
xorpd %xmm1, %xmm1
cmpq %r14, %r15
movsd %xmm3, 0x48(%rsp)
movsd %xmm2, 0x40(%rsp)
movsd %xmm4, 0x38(%rsp)
je 0x401c63
movl (%r13,%r14,4), %eax
cvtsi2sd %rax, %xmm5
movsd 0x58(%rsp), %xmm0
divsd %xmm5, %xmm0
movsd %xmm0, 0x60(%rsp)
movq %rbp, %rdi
movb $0x1, %al
movsd %xmm1, 0x68(%rsp)
callq 0x4108f0
movsd 0x68(%rsp), %xmm1
movsd 0x38(%rsp), %xmm4
movsd 0x40(%rsp), %xmm2
movsd 0x48(%rsp), %xmm3
movsd 0x60(%rsp), %xmm0
minsd %xmm0, %xmm2
maxsd %xmm0, %xmm3
addsd %xmm0, %xmm4
mulsd %xmm0, %xmm0
addsd %xmm0, %xmm1
incq %r14
jmp 0x401beb
movapd %xmm4, %xmm0
mulsd %xmm4, %xmm0
divsd 0x70(%rsp), %xmm0
subsd %xmm0, %xmm1
divsd 0x80(%rsp), %xmm1
ucomisd 0xb53b2(%rip), %xmm1    # 0x4b7038
jb 0x401c8e
sqrtsd %xmm1, %xmm1
jmp 0x401cad
movapd %xmm1, %xmm0
callq 0x402110
movsd 0x38(%rsp), %xmm4
movsd 0x40(%rsp), %xmm2
movsd 0x48(%rsp), %xmm3
movapd %xmm0, %xmm1
divsd 0x70(%rsp), %xmm4
movq 0x50(%rsp), %rdi
movapd %xmm4, %xmm0
movb $0x4, %al
callq 0x4108f0
movq $0x4eb710, %rax         # imm = 0x4EB710
movq (%rax), %rdi
callq 0x417480
incq %r12
movq %rbx, %r14
jmp 0x401b2f
movl 0x2c(%rsp), %eax
incl %eax
jmp 0x401b10
incl 0xef636(%rip)           # 0x4f1324
jmp 0x401ad8
xorl %eax, %eax
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq $0x4eb708, %rax         # imm = 0x4EB708
movq (%rax), %rdi
movq (%rbx), %rdx
leaq 0xb5330(%rip), %rsi     # 0x4b704b
xorl %eax, %eax
callq 0x410830
jmp 0x401d30
leaq 0xb5519(%rip), %rdi     # 0x4b7244
callq 0x410b20
pushq $0x1
popq %rdi
callq 0x40b480
leaq 0xb54f3(%rip), %rdi     # 0x4b7232
jmp 0x401d2b