// File: /workspace/github_c_makefile_star2_O1/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 $0x128, %rsp            # imm = 0x128
movq %rsi, %rbx
movl %edi, %ebp
movq $0x0, 0xebaf7(%rip) # 0x4ed310
movl $0x1, %eax
movq %rax, 0x18(%rsp)
movl $0x7a120, %eax          # imm = 0x7A120
movq %rax, 0x58(%rsp)
movb $0x20, 0x7(%rsp)
movl $0x6, %eax
movq %rax, 0x28(%rsp)
leaq 0xb57fd(%rip), %r15     # 0x4b7040
movq $0x4f6360, %r14         # imm = 0x4F6360
movl %ebp, %edi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x463630
cmpl $0x64, %eax
jne 0x401871
movq (%r14), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x40b860
movq %rax, 0xebaa1(%rip)     # 0x4ed310
jmp 0x40184a
cmpl $0x6d, %eax
jle 0x4018c1
cmpl $0x6e, %eax
je 0x4018f3
cmpl $0x73, %eax
je 0x4018dd
cmpl $0x74, %eax
jne 0x401e26
movq (%r14), %rdi
xorl %esi, %esi
callq 0x40bd70
mulss 0xb5769(%rip), %xmm0    # 0x4b7004
cvttss2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subss 0xb5759(%rip), %xmm0    # 0x4b7008
cvttss2si %xmm0, %rdx
andq %rcx, %rdx
orq %rax, %rdx
movq %rdx, 0x58(%rsp)
jmp 0x40184a
cmpl $-0x1, %eax
je 0x401926
cmpl $0x53, %eax
jne 0x401e26
movq (%r14), %rax
movb (%rax), %al
movb %al, 0x7(%rsp)
jmp 0x40184a
movq (%r14), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x40b860
movq %rax, 0x18(%rsp)
jmp 0x40184a
movq (%r14), %rdi
xorl %esi, %esi
callq 0x40bd70
cvttss2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subss 0xb56f7(%rip), %xmm0    # 0x4b7008
cvttss2si %xmm0, %rdx
andq %rcx, %rdx
orq %rax, %rdx
movq %rdx, 0x28(%rsp)
jmp 0x40184a
movq $0x4ec0a0, %rax         # imm = 0x4EC0A0
cmpl %ebp, (%rax)
jne 0x401e26
movq $0x4eb710, %rax         # imm = 0x4EB710
movq (%rax), %rdi
movl $0x2000, %ecx           # imm = 0x2000
xorl %esi, %esi
movl $0x2, %edx
callq 0x417b80
callq 0x461f60
leaq 0xa8(%rsp), %rdx
movl $0x80, %esi
movl %eax, %edi
callq 0x463830
testl %eax, %eax
jne 0x401e33
xorl %eax, %eax
xorl %r14d, %r14d
movq %r14, %r15
movq %rax, %rcx
shrq $0x6, %rcx
movq 0xa8(%rsp,%rcx,8), %rdx
movl %eax, %ecx
andl $0x3f, %ecx
movq %rdx, %rbx
shrq %cl, %rbx
btq %rcx, %rdx
adcq $0x0, %r14
incq %rax
cmpq $0x400, %rax            # imm = 0x400
jne 0x401976
movl $0x400, %esi            # imm = 0x400
movq %r14, %rdi
callq 0x42bbf0
movq %rax, 0x20(%rsp)
leaq 0x1(%r14), %rax
movq %rax, 0xeb955(%rip)     # 0x4ed318
movq %r14, 0x8(%rsp)
testq %r14, %r14
je 0x401a39
xorl %r14d, %r14d
leaq 0x461(%rip), %r12       # 0x401e38
leaq 0x48(%rsp), %r13
xorl %ebp, %ebp
cmpl $0x3ff, %ebp            # imm = 0x3FF
ja 0x4019f9
movl %ebp, %eax
shrl $0x6, %eax
movq 0xa8(%rsp,%rax,8), %rax
btq %rbp, %rax
jb 0x4019fd
incl %ebp
jmp 0x4019de
movq %r14, %rax
shlq $0xa, %rax
movq 0x20(%rsp), %rdx
leaq (%rdx,%rax), %rcx
movl %ebp, 0x4(%rdx,%rax)
movl $0x0, (%rdx,%rax)
movq %r13, %rdi
xorl %esi, %esi
movq %r12, %rdx
callq 0x421cc0
testl %eax, %eax
jne 0x401e2e
incl %ebp
incq %r14
cmpq 0x8(%rsp), %r14
jne 0x4019de
callq 0x402199
movl $0x4, %esi
movq 0x8(%rsp), %r12
movq %r12, %rdi
callq 0x42bbf0
movq %rax, %r13
leaq 0xb58a5(%rip), %rdi     # 0x4b72ff
callq 0x4179e0
cmpb $0x2c, 0x7(%rsp)
leaq 0xb57e8(%rip), %rax     # 0x4b7253
leaq 0xb5810(%rip), %rdi     # 0x4b7282
cmoveq %rax, %rdi
leaq 0xb57e4(%rip), %rax     # 0x4b7261
leaq 0xb57f8(%rip), %r14     # 0x4b727c
cmoveq %rax, %r14
leaq 0xb57da(%rip), %rax     # 0x4b7269
leaq 0xd171f(%rip), %rcx     # 0x4d31b5
cmoveq %rax, %rcx
movq %rcx, 0x10(%rsp)
xorl %eax, %eax
callq 0x4109c0
testq %r12, %r12
je 0x401ad7
movl %ebx, %r12d
andl $0x1, %r12d
addq %r15, %r12
movq 0x20(%rsp), %rbp
addq $0x4, %rbp
movl (%rbp), %esi
movq %r14, %rdi
xorl %eax, %eax
callq 0x4109c0
addq $0x400, %rbp            # imm = 0x400
decq %r12
jne 0x401abe
movq 0x10(%rsp), %rdi
callq 0x4179e0
xorl %eax, %eax
movl %eax, 0xef837(%rip)     # 0x4f1320
movl %eax, 0xef835(%rip)     # 0x4f1324
movl 0xef82f(%rip), %eax     # 0x4f1324
cmpl $0x1, %eax
movq 0x8(%rsp), %r12
jg 0x401e12
cmpb $0x2c, 0x7(%rsp)
leaq 0xb5798(%rip), %rax     # 0x4b72a7
leaq 0xb57a7(%rip), %rcx     # 0x4b72bd
cmoveq %rax, %rcx
movq %rcx, 0x60(%rsp)
movq %r12, %xmm0
movq 0xb54e4(%rip), %xmm1    # 0x4b7010
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0xb54e8(%rip), %xmm2    # 0x4b7020
subpd %xmm2, %xmm0
movapd %xmm0, %xmm3
unpckhpd %xmm0, %xmm3            # xmm3 = xmm3[1],xmm0[1]
addsd %xmm0, %xmm3
movapd %xmm3, 0x80(%rsp)
leaq -0x1(%r12), %rax
movq %rax, %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, 0x90(%rsp)
andl $0x1, %ebx
addq %rbx, %r15
cmpb $0x2c, 0x7(%rsp)
je 0x401ba5
cmpl $0x0, 0xef798(%rip)     # 0x4f1324
leaq 0xb56f6(%rip), %rdi     # 0x4b7289
leaq 0xb56ed(%rip), %rax     # 0x4b7287
cmoveq %rax, %rdi
xorl %eax, %eax
callq 0x4109c0
cmpl $0x0, 0x18(%rsp)
jle 0x401dfd
xorl %eax, %eax
movl %eax, 0x44(%rsp)
movl %eax, 0xef764(%rip)     # 0x4f1320
movl $0x1, %edi
leaq 0x48(%rsp), %rsi
callq 0x461dd0
cmpq $-0x1, 0x28(%rsp)
je 0x401ded
imulq $0x3b9aca00, 0x48(%rsp), %rbp # imm = 0x3B9ACA00
addq 0x50(%rsp), %rbp
xorl %ebx, %ebx
movq 0x58(%rsp), %rdi
callq 0x464970
testq %r12, %r12
je 0x401c14
movq 0x20(%rsp), %rax
xorl %ecx, %ecx
xorl %edx, %edx
xchgl %edx, (%rax)
movl %edx, (%r13,%rcx,4)
incq %rcx
addq $0x400, %rax            # imm = 0x400
cmpq %rcx, %r15
jne 0x401bfd
movl $0x1, %edi
leaq 0x48(%rsp), %rsi
callq 0x461dd0
imulq $0x3b9aca00, 0x48(%rsp), %r14 # imm = 0x3B9ACA00
addq 0x50(%rsp), %r14
testq %rbx, %rbx
je 0x401dd8
cmpb $0x2c, 0x7(%rsp)
jne 0x401c73
movl 0xef6dd(%rip), %esi     # 0x4f1324
movslq 0xef6d2(%rip), %rdx     # 0x4f1320
shlq $0x6, %rdx
leaq 0xeb6c7(%rip), %rax     # 0x4ed320
addq %rax, %rdx
leaq 0xb5630(%rip), %rdi     # 0x4b7293
xorl %eax, %eax
callq 0x4109c0
leaq 0xb5628(%rip), %r12     # 0x4b7299
jmp 0x401c88
leaq 0xb5605(%rip), %rdi     # 0x4b727f
xorl %eax, %eax
callq 0x4109c0
leaq 0xb5617(%rip), %r12     # 0x4b729f
cmpq $0x0, 0x8(%rsp)
je 0x401d38
movq %r14, %rax
subq %rbp, %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x68(%rsp)
xorpd %xmm1, %xmm1
xorps %xmm4, %xmm4
xorpd %xmm3, %xmm3
movsd 0xb5375(%rip), %xmm2    # 0x4b7030
xorl %ebp, %ebp
movsd %xmm1, 0x78(%rsp)
movsd %xmm4, 0x30(%rsp)
movsd %xmm2, 0x38(%rsp)
movsd %xmm3, 0x10(%rsp)
movl (%r13,%rbp,4), %eax
xorps %xmm1, %xmm1
cvtsi2sd %rax, %xmm1
movsd 0x68(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x70(%rsp)
movq %r12, %rdi
movb $0x1, %al
callq 0x4109c0
movsd 0x78(%rsp), %xmm1
movsd 0x30(%rsp), %xmm4
movsd 0x38(%rsp), %xmm2
movsd 0x10(%rsp), %xmm3
movsd 0x70(%rsp), %xmm0
minsd %xmm0, %xmm2
maxsd %xmm0, %xmm3
addsd %xmm0, %xmm4
mulsd %xmm0, %xmm0
addsd %xmm0, %xmm1
incq %rbp
cmpq %rbp, %r15
jne 0x401cbd
jmp 0x401d4c
xorpd %xmm3, %xmm3
movsd 0xb52ec(%rip), %xmm2    # 0x4b7030
xorpd %xmm4, %xmm4
xorpd %xmm1, %xmm1
movapd %xmm4, %xmm0
mulsd %xmm4, %xmm0
divsd 0x80(%rsp), %xmm0
subsd %xmm0, %xmm1
divsd 0x90(%rsp), %xmm1
ucomisd 0xb52c6(%rip), %xmm1    # 0x4b7038
jb 0x401d7a
sqrtsd %xmm1, %xmm1
jmp 0x401dab
movapd %xmm1, %xmm0
movsd %xmm3, 0x10(%rsp)
movsd %xmm2, 0x38(%rsp)
movsd %xmm4, 0x30(%rsp)
callq 0x4021e0
movsd 0x30(%rsp), %xmm4
movsd 0x38(%rsp), %xmm2
movsd 0x10(%rsp), %xmm3
movapd %xmm0, %xmm1
movq 0x8(%rsp), %r12
divsd 0x80(%rsp), %xmm4
movq 0x60(%rsp), %rdi
movapd %xmm4, %xmm0
movb $0x4, %al
callq 0x4109c0
movq $0x4eb710, %rax         # imm = 0x4EB710
movq (%rax), %rdi
callq 0x417550
leaq 0x1(%rbx), %rax
movq %r14, %rbp
cmpq 0x28(%rsp), %rbx
movq %rax, %rbx
jne 0x401be7
movl 0x44(%rsp), %eax
incl %eax
cmpl 0x18(%rsp), %eax
jne 0x401bb2
incl 0xef521(%rip)           # 0x4f1324
movl 0xef51b(%rip), %eax     # 0x4f1324
cmpl $0x2, %eax
jl 0x401b7e
xorl %eax, %eax
addq $0x128, %rsp            # imm = 0x128
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rbx, %rdi
callq 0x40116a
callq 0x401155
callq 0x401140