// File: /workspace/github_c_makefile_star2_O3/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, 0x10(%rsp)
movl $0x7a120, %eax          # imm = 0x7A120
movq %rax, 0x58(%rsp)
movb $0x20, 0xf(%rsp)
movl $0x6, %eax
movq %rax, 0x20(%rsp)
leaq 0xb583d(%rip), %r15     # 0x4b7080
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 0x40b880
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 0x401e45
movq (%r14), %rdi
xorl %esi, %esi
callq 0x40bd90
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 0x401e45
movq (%r14), %rax
movb (%rax), %al
movb %al, 0xf(%rsp)
jmp 0x40184a
movq (%r14), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x40b880
movq %rax, 0x10(%rsp)
jmp 0x40184a
movq (%r14), %rdi
xorl %esi, %esi
callq 0x40bd90
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, 0x20(%rsp)
jmp 0x40184a
movq $0x4ec0a0, %rax         # imm = 0x4EC0A0
cmpl %ebp, (%rax)
jne 0x401e45
movq $0x4eb710, %rax         # imm = 0x4EB710
movq (%rax), %rdi
movl $0x2000, %ecx           # imm = 0x2000
xorl %esi, %esi
movl $0x2, %edx
callq 0x417ba0
callq 0x461f60
leaq 0xa8(%rsp), %rdx
movl $0x80, %esi
movl %eax, %edi
callq 0x463830
testl %eax, %eax
jne 0x401e52
pxor %xmm0, %xmm0
movdqa 0xb5693(%rip), %xmm1    # 0x4b7010
xorl %eax, %eax
movdqa 0xb5699(%rip), %xmm2    # 0x4b7020
movapd 0xb56a1(%rip), %xmm3    # 0x4b7030
movdqa 0xb56a9(%rip), %xmm4    # 0x4b7040
movq %rax, %rcx
shrq $0x6, %rcx
movq 0xa8(%rsp,%rcx,8), %xmm5
pshufd $0x44, %xmm5, %xmm6     # xmm6 = xmm5[0,1,0,1]
movdqa %xmm1, %xmm7
pand %xmm2, %xmm7
psrlq %xmm7, %xmm5
pshufd $0xee, %xmm7, %xmm7     # xmm7 = xmm7[2,3,2,3]
psrlq %xmm7, %xmm6
movsd %xmm5, %xmm6            # xmm6 = xmm5[0],xmm6[1]
andpd %xmm3, %xmm6
paddq %xmm6, %xmm0
addq $0x2, %rax
paddq %xmm4, %xmm1
cmpq $0x400, %rax            # imm = 0x400
jne 0x401997
pshufd $0xee, %xmm0, %xmm1     # xmm1 = xmm0[2,3,2,3]
paddq %xmm0, %xmm1
movq %xmm1, %r15
movl $0x400, %esi            # imm = 0x400
movq %r15, %rdi
callq 0x42bc10
movq %rax, 0x18(%rsp)
leaq 0x1(%r15), %rax
movq %rax, 0xeb910(%rip)     # 0x4ed318
testq %r15, %r15
je 0x401a7d
xorl %r14d, %r14d
leaq 0x440(%rip), %rbx       # 0x401e57
leaq 0x48(%rsp), %r12
xorl %r13d, %r13d
cmpl $0x3ff, %r13d           # imm = 0x3FF
ja 0x401a3c
movl %r13d, %eax
shrl $0x6, %eax
movq 0xa8(%rsp,%rax,8), %rax
btq %r13, %rax
jb 0x401a41
incl %r13d
jmp 0x401a1f
movq %r14, %rax
shlq $0xa, %rax
movq 0x18(%rsp), %rdx
leaq (%rdx,%rax), %rcx
movl %r13d, 0x4(%rdx,%rax)
movl $0x0, (%rdx,%rax)
movq %r12, %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0x421ce0
testl %eax, %eax
jne 0x401e4d
incl %r13d
incq %r14
cmpq %r15, %r14
jne 0x401a1f
callq 0x4021b8
movl $0x4, %esi
movq %r15, %rdi
callq 0x42bc10
movq %rax, %r13
leaq 0xb58a6(%rip), %rdi     # 0x4b733f
callq 0x417a00
cmpb $0x2c, 0xf(%rsp)
leaq 0xb57e9(%rip), %rax     # 0x4b7293
leaq 0xb5811(%rip), %rdi     # 0x4b72c2
cmoveq %rax, %rdi
leaq 0xb57e5(%rip), %rax     # 0x4b72a1
leaq 0xb57f9(%rip), %rbx     # 0x4b72bc
cmoveq %rax, %rbx
leaq 0xb57db(%rip), %rax     # 0x4b72a9
leaq 0xd1720(%rip), %r12     # 0x4d31f5
cmoveq %rax, %r12
xorl %eax, %eax
callq 0x4109e0
testq %r15, %r15
je 0x401b0a
movq 0x18(%rsp), %r14
addq $0x4, %r14
movq %r15, %rbp
movl (%r14), %esi
movq %rbx, %rdi
xorl %eax, %eax
callq 0x4109e0
addq $0x400, %r14            # imm = 0x400
decq %rbp
jne 0x401af1
movq %r12, %rdi
callq 0x417a00
xorl %eax, %eax
movl %eax, 0xef806(%rip)     # 0x4f1320
movl %eax, 0xef804(%rip)     # 0x4f1324
movl 0xef7fe(%rip), %eax     # 0x4f1324
cmpl $0x1, %eax
jg 0x401e31
cmpb $0x2c, 0xf(%rsp)
leaq 0xb57ac(%rip), %rax     # 0x4b72e7
leaq 0xb57bb(%rip), %rcx     # 0x4b72fd
cmoveq %rax, %rcx
movq %rcx, 0x60(%rsp)
movq %r15, %xmm0
movq 0xb54f8(%rip), %xmm1    # 0x4b7050
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0xb54fc(%rip), %xmm2    # 0x4b7060
subpd %xmm2, %xmm0
movapd %xmm0, %xmm3
unpckhpd %xmm0, %xmm3            # xmm3 = xmm3[1],xmm0[1]
addsd %xmm0, %xmm3
movapd %xmm3, 0x80(%rsp)
leaq -0x1(%r15), %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)
cmpb $0x2c, 0xf(%rsp)
je 0x401bca
cmpl $0x0, 0xef773(%rip)     # 0x4f1324
leaq 0xb5711(%rip), %rdi     # 0x4b72c9
leaq 0xb5708(%rip), %rax     # 0x4b72c7
cmoveq %rax, %rdi
xorl %eax, %eax
callq 0x4109e0
cmpl $0x0, 0x10(%rsp)
jle 0x401e1c
xorl %eax, %eax
movl %eax, 0x44(%rsp)
movl %eax, 0xef73f(%rip)     # 0x4f1320
movl $0x1, %edi
leaq 0x48(%rsp), %rsi
callq 0x461dd0
cmpq $-0x1, 0x20(%rsp)
je 0x401e0c
imulq $0x3b9aca00, 0x48(%rsp), %rbx # imm = 0x3B9ACA00
addq 0x50(%rsp), %rbx
xorl %r14d, %r14d
movq 0x58(%rsp), %rdi
callq 0x464970
testq %r15, %r15
je 0x401c3a
movq 0x18(%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 0x401c23
movl $0x1, %edi
leaq 0x48(%rsp), %rsi
callq 0x461dd0
imulq $0x3b9aca00, 0x48(%rsp), %rbp # imm = 0x3B9ACA00
addq 0x50(%rsp), %rbp
testq %r14, %r14
je 0x401df7
cmpb $0x2c, 0xf(%rsp)
jne 0x401c99
movl 0xef6b7(%rip), %esi     # 0x4f1324
movslq 0xef6ac(%rip), %rdx     # 0x4f1320
shlq $0x6, %rdx
leaq 0xeb6a1(%rip), %rax     # 0x4ed320
addq %rax, %rdx
leaq 0xb564a(%rip), %rdi     # 0x4b72d3
xorl %eax, %eax
callq 0x4109e0
leaq 0xb5642(%rip), %r12     # 0x4b72d9
jmp 0x401cae
leaq 0xb561f(%rip), %rdi     # 0x4b72bf
xorl %eax, %eax
callq 0x4109e0
leaq 0xb5631(%rip), %r12     # 0x4b72df
testq %r15, %r15
je 0x401d5c
movq %rbp, %rax
subq %rbx, %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x68(%rsp)
xorpd %xmm1, %xmm1
pxor %xmm4, %xmm4
xorpd %xmm3, %xmm3
movsd 0xb5391(%rip), %xmm2    # 0x4b7070
xorl %ebx, %ebx
movsd %xmm1, 0x78(%rsp)
movq %xmm4, 0x28(%rsp)
movsd %xmm2, 0x30(%rsp)
movsd %xmm3, 0x38(%rsp)
movl (%r13,%rbx,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 0x4109e0
movsd 0x78(%rsp), %xmm1
movsd 0x28(%rsp), %xmm4
movsd 0x30(%rsp), %xmm2
movsd 0x38(%rsp), %xmm3
movsd 0x70(%rsp), %xmm0
minsd %xmm0, %xmm2
maxsd %xmm0, %xmm3
addsd %xmm0, %xmm4
mulsd %xmm0, %xmm0
addsd %xmm0, %xmm1
incq %rbx
cmpq %rbx, %r15
jne 0x401ce1
jmp 0x401d70
xorpd %xmm3, %xmm3
movsd 0xb5308(%rip), %xmm2    # 0x4b7070
pxor %xmm4, %xmm4
xorpd %xmm1, %xmm1
movapd %xmm4, %xmm0
mulsd %xmm4, %xmm0
divsd 0x80(%rsp), %xmm0
subsd %xmm0, %xmm1
divsd 0x90(%rsp), %xmm1
ucomisd 0xb52e2(%rip), %xmm1    # 0x4b7078
jb 0x401d9e
sqrtsd %xmm1, %xmm1
jmp 0x401dcf
movapd %xmm1, %xmm0
movsd %xmm3, 0x38(%rsp)
movsd %xmm2, 0x30(%rsp)
movsd %xmm4, 0x28(%rsp)
callq 0x402200
movsd 0x28(%rsp), %xmm4
movsd 0x30(%rsp), %xmm2
movsd 0x38(%rsp), %xmm3
movapd %xmm0, %xmm1
divsd 0x80(%rsp), %xmm4
movq 0x60(%rsp), %rdi
movapd %xmm4, %xmm0
movb $0x4, %al
callq 0x4109e0
movq $0x4eb710, %rax         # imm = 0x4EB710
movq (%rax), %rdi
callq 0x417570
leaq 0x1(%r14), %rax
movq %rbp, %rbx
cmpq 0x20(%rsp), %r14
movq %rax, %r14
jne 0x401c0d
movl 0x44(%rsp), %eax
incl %eax
cmpl 0x10(%rsp), %eax
jne 0x401bd7
incl 0xef502(%rip)           # 0x4f1324
movl 0xef4fc(%rip), %eax     # 0x4f1324
cmpl $0x2, %eax
jl 0x401ba3
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