// File: /workspace/github_c_makefile_star2_O0/google[P]multichase/pingpong.c
// Function: main
int main(int argc, char **argv) {
  void *(*thread_fn)(void *data) = NULL;
  int c;
  char *p;

  while ((c = getopt(argc, argv, "c:lur:xs:")) != -1) {
    switch (c) {
      case 'l':
        if (thread_fn) goto thread_fn_error;
        thread_fn = locked_loop;
        break;
      case 'u':
        if (thread_fn) goto thread_fn_error;
        thread_fn = unlocked_loop;
        break;
      case 'x':
        if (thread_fn) goto thread_fn_error;
        thread_fn = xadd_loop;
        break;
      case 'r':
        nr_relax = strtoul(optarg, &p, 0);
        if (*p) {
          fprintf(stderr, "-r requires a numeric argument\n");
          exit(1);
        }
        break;
      case 'c':
        nr_tested_cores = strtoul(optarg, &p, 0);
        if (*p) {
          fprintf(stderr, "-c requires a numeric argument\n");
          exit(1);
        }
        break;
      case 's':
        nr_array_elts = strtoul(optarg, &p, 0);
        if (*p) {
          fprintf(stderr, "-s requires a numeric argument\n");
          exit(1);
        }
        if (posix_memalign((void **)&communication_array, 1ull << 21,
                           nr_array_elts * sizeof(*communication_array))) {
          fprintf(stderr, "posix_memalign failed\n");
          exit(1);
        }
        break;
      default:
        fprintf(stderr,
                "usage: %s [-l | -u | -x] [-r nr_relax] [-s "
                "nr_array_elts_to_dirty] [-c nr_tested_cores]\n",
                argv[0]);
        exit(1);
    }
  }
  if (thread_fn == NULL) {
  thread_fn_error:
    fprintf(stderr, "must specify exactly one of -u, -l or -x\n");
    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);
  }

  printf(
      "avg latency to communicate a modified line from one core to another\n");
  printf("times are in ns\n\n");

  // print top row header
  const int col_width = 8;
  size_t first_cpu = ~0;
  size_t last_cpu = 0;
  printf("   ");
  for (size_t j = 0; j < CPU_SETSIZE; ++j) {
    if (CPU_ISSET(j, &cpus)) {
      if (first_cpu > j) {
        first_cpu = j;
      } else {
        printf("%*zu", col_width, j);
      }
      if (last_cpu < j) {
        last_cpu = j;
      }
    }
  }
  printf("\n");

  for (size_t i = 0, core = 0; i < last_cpu && core < nr_tested_cores; ++i) {
    if (!CPU_ISSET(i, &cpus)) {
      continue;
    }
    ++core;
    thread_args_t even;
    CPU_ZERO(&even.cpus);
    CPU_SET(i, &even.cpus);
    even.me = 0;
    even.buddy = 1;
    printf("%2zu:", i);
    for (size_t j = first_cpu + 1; j <= i; ++j) {
      if (CPU_ISSET(j, &cpus)) {
        printf("%*s", col_width, "");
      }
    }
    for (size_t j = i + 1; j <= last_cpu; ++j) {
      if (!CPU_ISSET(j, &cpus)) {
        continue;
      }

      thread_args_t odd;
      CPU_ZERO(&odd.cpus);
      CPU_SET(j, &odd.cpus);
      odd.me = 1;
      odd.buddy = 0;
      __sync_lock_test_and_set(&nr_pingpongs.x, 0);
      pthread_t odd_thread;
      if (pthread_create(&odd_thread, NULL, thread_fn, &odd)) {
        perror("pthread_create odd");
        exit(1);
      }
      pthread_t even_thread;
      if (pthread_create(&even_thread, NULL, thread_fn, &even)) {
        perror("pthread_create even");
        exit(1);
      }

      uint64_t last_stamp = now_nsec();
      double best_sample = 1. / 0.;  // infinity
      for (size_t sample_no = 0; sample_no < NR_SAMPLES; ++sample_no) {
        usleep(SAMPLE_US);
        atomic_t s = __sync_lock_test_and_set(&nr_pingpongs.x, 0);
        uint64_t time_stamp = now_nsec();
        double sample = (time_stamp - last_stamp) / (double)s;
        last_stamp = time_stamp;
        if (sample < best_sample) {
          best_sample = sample;
        }
      }
      printf("%*.1f", col_width, best_sample);

      stop_loops = 1;
      if (pthread_join(odd_thread, NULL)) {
        perror("pthread_join odd_thread");
        exit(1);
      }
      if (pthread_join(even_thread, NULL)) {
        perror("pthread_join even_thread");
        exit(1);
      }
      stop_loops = 0;

      if (munmap(pingpong_mutex, getpagesize())) {
        perror("munmap");
        exit(1);
      }
      pingpong_mutex = NULL;
    }
    printf("\n");
  }
  printf("\n");

  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2d0, %rsp            # imm = 0x2D0
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq $0x0, -0x18(%rbp)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0xb3939(%rip), %rdx     # 0x4b5088
callq 0x456d60
movl %eax, -0x1c(%rbp)
cmpl $-0x1, %eax
je 0x401935
movl -0x1c(%rbp), %eax
addl $-0x63, %eax
movl %eax, %ecx
movq %rcx, -0x2a0(%rbp)
subl $0x15, %eax
ja 0x401907
movq -0x2a0(%rbp), %rax
leaq 0xb38aa(%rip), %rcx     # 0x4b5030
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
cmpq $0x0, -0x18(%rbp)
je 0x40179b
jmp 0x40193e
leaq 0x9be(%rip), %rax       # 0x402160
movq %rax, -0x18(%rbp)
jmp 0x401930
cmpq $0x0, -0x18(%rbp)
je 0x4017b7
jmp 0x40193e
leaq 0xab2(%rip), %rax       # 0x402270
movq %rax, -0x18(%rbp)
jmp 0x401930
cmpq $0x0, -0x18(%rbp)
je 0x4017d3
jmp 0x40193e
leaq 0xba6(%rip), %rax       # 0x402380
movq %rax, -0x18(%rbp)
jmp 0x401930
movq $0x4f0040, %rax         # imm = 0x4F0040
movq (%rax), %rdi
leaq -0x28(%rbp), %rsi
xorl %edx, %edx
callq 0x40bc50
movq %rax, 0xe6911(%rip)     # 0x4e8110
movq -0x28(%rbp), %rax
cmpb $0x0, (%rax)
je 0x40182a
movq $0x4e8728, %rax         # imm = 0x4E8728
movq (%rax), %rdi
leaq 0xb3879(%rip), %rsi     # 0x4b5092
movb $0x0, %al
callq 0x40c470
movl $0x1, %edi
callq 0x40b940
jmp 0x401930
movq $0x4f0040, %rax         # imm = 0x4F0040
movq (%rax), %rdi
leaq -0x28(%rbp), %rsi
xorl %edx, %edx
callq 0x40bc50
movq %rax, 0xe68cd(%rip)     # 0x4e8118
movq -0x28(%rbp), %rax
cmpb $0x0, (%rax)
je 0x401876
movq $0x4e8728, %rax         # imm = 0x4E8728
movq (%rax), %rdi
leaq 0xb384d(%rip), %rsi     # 0x4b50b2
movb $0x0, %al
callq 0x40c470
movl $0x1, %edi
callq 0x40b940
jmp 0x401930
movq $0x4f0040, %rax         # imm = 0x4F0040
movq (%rax), %rdi
leaq -0x28(%rbp), %rsi
xorl %edx, %edx
callq 0x40bc50
movq %rax, 0xe8f69(%rip)     # 0x4ea800
movq -0x28(%rbp), %rax
cmpb $0x0, (%rax)
je 0x4018c2
movq $0x4e8728, %rax         # imm = 0x4E8728
movq (%rax), %rdi
leaq 0xb3821(%rip), %rsi     # 0x4b50d2
movb $0x0, %al
callq 0x40c470
movl $0x1, %edi
callq 0x40b940
movq 0xe8f37(%rip), %rdx     # 0x4ea800
shlq $0x3, %rdx
leaq 0xe8f34(%rip), %rdi     # 0x4ea808
movl $0x200000, %esi         # imm = 0x200000
callq 0x4285c0
cmpl $0x0, %eax
je 0x401905
movq $0x4e8728, %rax         # imm = 0x4E8728
movq (%rax), %rdi
leaq 0xb37fe(%rip), %rsi     # 0x4b50f2
movb $0x0, %al
callq 0x40c470
movl $0x1, %edi
callq 0x40b940
jmp 0x401930
movq $0x4e8728, %rax         # imm = 0x4E8728
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rdx
leaq 0xb37ea(%rip), %rsi     # 0x4b5109
movb $0x0, %al
callq 0x40c470
movl $0x1, %edi
callq 0x40b940
jmp 0x401741
cmpq $0x0, -0x18(%rbp)
jne 0x401960
jmp 0x40193e
movq $0x4e8728, %rax         # imm = 0x4E8728
movq (%rax), %rdi
leaq 0xb3813(%rip), %rsi     # 0x4b5162
movb $0x0, %al
callq 0x40c470
movl $0x1, %edi
callq 0x40b940
movq $0x4e8730, %rax         # imm = 0x4E8730
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x2, %edx
movl $0x2000, %ecx           # imm = 0x2000
callq 0x413550
callq 0x455690
movl %eax, %edi
movl $0x80, %esi
leaq -0xa8(%rbp), %rdx
callq 0x456f60
cmpl $0x0, %eax
je 0x4019b0
leaq 0xb37eb(%rip), %rdi     # 0x4b518c
callq 0x40c760
movl $0x1, %edi
callq 0x40b940
leaq 0xb37e7(%rip), %rdi     # 0x4b519e
movb $0x0, %al
callq 0x40c530
leaq 0xb381e(%rip), %rdi     # 0x4b51e3
movb $0x0, %al
callq 0x40c530
movl $0x8, -0xac(%rbp)
movq $-0x1, -0xb8(%rbp)
movq $0x0, -0xc0(%rbp)
leaq 0xb3802(%rip), %rdi     # 0x4b51f5
movb $0x0, %al
callq 0x40c530
movq $0x0, -0xc8(%rbp)
cmpq $0x400, -0xc8(%rbp) # imm = 0x400
jae 0x401b09
movq -0xc8(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x401a77
movq -0xd0(%rbp), %rax
shrq $0x6, %rax
movq -0xa8(%rbp,%rax,8), %rax
movq -0xd0(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %edx
shlq %cl, %rdx
movq %rdx, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x2a4(%rbp)
jmp 0x401a81
xorl %eax, %eax
movl %eax, -0x2a4(%rbp)
jmp 0x401a81
movl -0x2a4(%rbp), %eax
movl %eax, -0xd4(%rbp)
cmpl $0x0, -0xd4(%rbp)
je 0x401af0
movq -0xb8(%rbp), %rax
cmpq -0xc8(%rbp), %rax
jbe 0x401ab6
movq -0xc8(%rbp), %rax
movq %rax, -0xb8(%rbp)
jmp 0x401ad0
movq -0xc8(%rbp), %rdx
leaq 0xb3735(%rip), %rdi     # 0x4b51f9
movl $0x8, %esi
movb $0x0, %al
callq 0x40c530
movq -0xc0(%rbp), %rax
cmpq -0xc8(%rbp), %rax
jae 0x401aee
movq -0xc8(%rbp), %rax
movq %rax, -0xc0(%rbp)
jmp 0x401af0
jmp 0x401af2
movq -0xc8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc8(%rbp)
jmp 0x401a05
leaq 0xb3cfa(%rip), %rdi     # 0x4b580a
movb $0x0, %al
callq 0x40c530
movq $0x0, -0xe0(%rbp)
movq $0x0, -0xe8(%rbp)
movq -0xe0(%rbp), %rcx
xorl %eax, %eax
cmpq -0xc0(%rbp), %rcx
movb %al, -0x2a5(%rbp)
jae 0x401b5c
movq -0xe8(%rbp), %rax
cmpq 0xe65c5(%rip), %rax     # 0x4e8118
setb %al
movb %al, -0x2a5(%rbp)
movb -0x2a5(%rbp), %al
testb $0x1, %al
jne 0x401b6b
jmp 0x40213f
movq -0xe0(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x401bcc
movq -0xf0(%rbp), %rax
shrq $0x6, %rax
movq -0xa8(%rbp,%rax,8), %rax
movq -0xf0(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %edx
shlq %cl, %rdx
movq %rdx, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x2ac(%rbp)
jmp 0x401bd6
xorl %eax, %eax
movl %eax, -0x2ac(%rbp)
jmp 0x401bd6
movl -0x2ac(%rbp), %eax
movl %eax, -0xf4(%rbp)
cmpl $0x0, -0xf4(%rbp)
jne 0x401bf0
jmp 0x402128
movq -0xe8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xe8(%rbp)
leaq -0x180(%rbp), %rdi
xorl %esi, %esi
movl $0x80, %edx
callq 0x4010a8
movq -0xe0(%rbp), %rax
movq %rax, -0x188(%rbp)
movq -0x188(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x401c6d
movq -0x188(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
movq -0x188(%rbp), %rcx
shrq $0x6, %rcx
orq -0x180(%rbp,%rcx,8), %rax
movq %rax, -0x180(%rbp,%rcx,8)
movq %rax, -0x2b8(%rbp)
jmp 0x401c78
xorl %eax, %eax
movq %rax, -0x2b8(%rbp)
jmp 0x401c78
movq -0x2b8(%rbp), %rax
movq %rax, -0x190(%rbp)
movl $0x0, -0x100(%rbp)
movl $0x1, -0xfc(%rbp)
movq -0xe0(%rbp), %rsi
leaq 0xb3556(%rip), %rdi     # 0x4b51fe
movb $0x0, %al
callq 0x40c530
movq -0xb8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x198(%rbp)
movq -0x198(%rbp), %rax
cmpq -0xe0(%rbp), %rax
ja 0x401d88
movq -0x198(%rbp), %rax
movq %rax, -0x1a0(%rbp)
movq -0x1a0(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x401d36
movq -0x1a0(%rbp), %rax
shrq $0x6, %rax
movq -0xa8(%rbp,%rax,8), %rax
movq -0x1a0(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %edx
shlq %cl, %rdx
movq %rdx, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x2bc(%rbp)
jmp 0x401d40
xorl %eax, %eax
movl %eax, -0x2bc(%rbp)
jmp 0x401d40
movl -0x2bc(%rbp), %eax
movl %eax, -0x1a4(%rbp)
cmpl $0x0, -0x1a4(%rbp)
je 0x401d6f
leaq 0xb34a8(%rip), %rdi     # 0x4b5204
movl $0x8, %esi
leaq 0xcb5ad(%rip), %rdx     # 0x4cd315
movb $0x0, %al
callq 0x40c530
jmp 0x401d71
movq -0x198(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x198(%rbp)
jmp 0x401cc1
movq -0xe0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x1b0(%rbp)
movq -0x1b0(%rbp), %rax
cmpq -0xc0(%rbp), %rax
ja 0x40211a
movq -0x1b0(%rbp), %rax
movq %rax, -0x1b8(%rbp)
movq -0x1b8(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x401e0f
movq -0x1b8(%rbp), %rax
shrq $0x6, %rax
movq -0xa8(%rbp,%rax,8), %rax
movq -0x1b8(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %edx
shlq %cl, %rdx
movq %rdx, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x2c0(%rbp)
jmp 0x401e19
xorl %eax, %eax
movl %eax, -0x2c0(%rbp)
jmp 0x401e19
movl -0x2c0(%rbp), %eax
movl %eax, -0x1bc(%rbp)
cmpl $0x0, -0x1bc(%rbp)
jne 0x401e33
jmp 0x402103
jmp 0x401e35
leaq -0x248(%rbp), %rdi
xorl %esi, %esi
movl $0x80, %edx
callq 0x4010a8
movq -0x1b0(%rbp), %rax
movq %rax, -0x250(%rbp)
movq -0x250(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x401ea0
movq -0x250(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
movq -0x250(%rbp), %rcx
shrq $0x6, %rcx
orq -0x248(%rbp,%rcx,8), %rax
movq %rax, -0x248(%rbp,%rcx,8)
movq %rax, -0x2c8(%rbp)
jmp 0x401eab
xorl %eax, %eax
movq %rax, -0x2c8(%rbp)
jmp 0x401eab
movq -0x2c8(%rbp), %rax
movq %rax, -0x258(%rbp)
movl $0x1, -0x1c8(%rbp)
movl $0x0, -0x1c4(%rbp)
xorl %eax, %eax
xchgl %eax, 0xe8d2b(%rip)     # 0x4eac00
movq -0x18(%rbp), %rdx
leaq -0x260(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
leaq -0x248(%rbp), %rcx
callq 0x41d690
cmpl $0x0, %eax
je 0x401f0b
leaq 0xb330c(%rip), %rdi     # 0x4b5208
callq 0x40c760
movl $0x1, %edi
callq 0x40b940
movq -0x18(%rbp), %rdx
leaq -0x268(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
leaq -0x180(%rbp), %rcx
callq 0x41d690
cmpl $0x0, %eax
je 0x401f41
leaq 0xb32e9(%rip), %rdi     # 0x4b521b
callq 0x40c760
movl $0x1, %edi
callq 0x40b940
callq 0x402480
movq %rax, -0x270(%rbp)
movsd 0xb30b3(%rip), %xmm0    # 0x4b5008
movsd %xmm0, -0x278(%rbp)
movq $0x0, -0x280(%rbp)
cmpq $0x5, -0x280(%rbp)
jae 0x402036
movl $0x3d090, %edi          # imm = 0x3D090
callq 0x4580a0
xorl %eax, %eax
xchgl %eax, 0xe8c78(%rip)     # 0x4eac00
movl %eax, -0x284(%rbp)
callq 0x402480
movq %rax, -0x290(%rbp)
movq -0x290(%rbp), %rax
movq -0x270(%rbp), %rcx
subq %rcx, %rax
movq %rax, %xmm0
movaps 0xb3059(%rip), %xmm1    # 0x4b5010
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0xb305d(%rip), %xmm1    # 0x4b5020
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movl -0x284(%rbp), %eax
cvtsi2sd %rax, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x298(%rbp)
movq -0x290(%rbp), %rax
movq %rax, -0x270(%rbp)
movsd -0x298(%rbp), %xmm1
movsd -0x278(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x40201d
movsd -0x298(%rbp), %xmm0
movsd %xmm0, -0x278(%rbp)
jmp 0x40201f
movq -0x280(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x280(%rbp)
jmp 0x401f68
movsd -0x278(%rbp), %xmm0
leaq 0xb31ea(%rip), %rdi     # 0x4b522f
movl $0x8, %esi
movb $0x1, %al
callq 0x40c530
movl $0x1, 0xe8fa5(%rip)     # 0x4eb000
movq -0x260(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x41e730
cmpl $0x0, %eax
je 0x402086
leaq 0xb31be(%rip), %rdi     # 0x4b5235
callq 0x40c760
movl $0x1, %edi
callq 0x40b940
movq -0x268(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x41e730
cmpl $0x0, %eax
je 0x4020b1
leaq 0xb31ab(%rip), %rdi     # 0x4b524d
callq 0x40c760
movl $0x1, %edi
callq 0x40b940
movl $0x0, 0xe8f45(%rip)     # 0x4eb000
movq 0xe8f46(%rip), %rax     # 0x4eb008
movq %rax, -0x2d0(%rbp)
callq 0x458010
movq -0x2d0(%rbp), %rdi
movslq %eax, %rsi
callq 0x458170
cmpl $0x0, %eax
je 0x4020f8
leaq 0xb317d(%rip), %rdi     # 0x4b5266
callq 0x40c760
movl $0x1, %edi
callq 0x40b940
movq $0x0, 0xe8f05(%rip) # 0x4eb008
movq -0x1b0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x1b0(%rbp)
jmp 0x401d9a
leaq 0xb36e9(%rip), %rdi     # 0x4b580a
movb $0x0, %al
callq 0x40c530
movq -0xe0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xe0(%rbp)
jmp 0x401b2d
leaq 0xb36c4(%rip), %rdi     # 0x4b580a
movb $0x0, %al
callq 0x40c530
xorl %eax, %eax
addq $0x2d0, %rsp            # imm = 0x2D0
popq %rbp
retq
nopl (%rax,%rax)