// File: /workspace/github_c_makefile_star2_O2/LPD-EPFL[P]mctop/src/mctop.c
// Function: mem_bandwidth
void*
mem_bandwidth(void* param)
{
  tld_t* tld = (tld_t*) param;
  const int tid = tld->id;
  const uint n_threads = tld->n_threads;
  pthread_barrier_t* barrier = tld->barrier;
  mctop_t* topo = tld->topo;
  const uint n_u64 = test_mem_bw_size / sizeof(uint64_t);

  volatile cache_line_t** mem_bw = malloc_assert(mctop_get_num_nodes(topo) * sizeof(cache_line_t*));
  for (int n = 0; n < mctop_get_num_nodes(topo); n++)
    {
      mem_bw[n] = numa_alloc_onnode(test_mem_bw_size, n);
      bzero((void*) mem_bw[n], test_mem_bw_size);
    }

  ID0_DO(mem_bw_gbps_r = (double*) malloc_assert(n_threads * sizeof(double));
	 mem_bw_gbps_w = (double*) malloc_assert(n_threads * sizeof(double)));

  double progress_step = 100.0 / (topo->n_sockets * topo->n_sockets);
  uint progress = 0;
  ID0_DO(NOT_VERBOSE(printf("# Progress : %6.1f%%", 0.0)); fflush(stdout));

  for (int n = 0; n < mctop_get_num_nodes(topo); n++)
    {
      mctop_run_on_socket_nm(topo, n);
      VERBOSE(ID0_DO(printf(" ######## Run Socket %d\n", n);););
      for (int mem_on = 0; mem_on < mctop_get_num_nodes(topo); mem_on++)
	{
	  VERBOSE(ID0_DO(printf(" #### Mem Node %d\n", mem_on)););

	  pthread_barrier_wait(barrier);
	  if (tid == 0)
	    {
	      dvfs_scale_up(test_num_dvfs_reps, test_dvfs_ratio, NULL);
	      double bw_gbps_r = mem_bw_estimate(mem_bw[mem_on], BW_READ, n_u64, test_mem_bw_num_reps);
	      mem_bw_table1_r[n][mem_on] = bw_gbps_r;
	      double bw_gbps_w = mem_bw_estimate(mem_bw[mem_on], BW_WRITE, n_u64, test_mem_bw_num_reps);
	      mem_bw_table1_w[n][mem_on] = bw_gbps_w;
	    }
	  pthread_barrier_wait(barrier);

	  dvfs_scale_up(test_num_dvfs_reps, test_dvfs_ratio, NULL);
	  mini_barrier(&mem_bw_barrier, n_threads);

	  double bw_gbps_r = mem_bw_estimate(mem_bw[mem_on], BW_READ, n_u64, test_mem_bw_num_reps);
	  mem_bw_gbps_r[tid] = bw_gbps_r;
	  double bw_gbps_w = mem_bw_estimate(mem_bw[mem_on], BW_WRITE, n_u64, test_mem_bw_num_reps);
	  mem_bw_gbps_w[tid] = bw_gbps_w;

	  pthread_barrier_wait(barrier);

	  if (tid == 0)
	    {
	      mem_bw_barrier = 0;
	      double tot_bw_r = 0, tot_bw_w = 0;
	      VERBOSE(printf("   READ  BW ("););
	      for (int i = 0; i < n_threads; i++)
		{
		  VERBOSE(printf("+%2.2f", mem_bw_gbps_r[i]););
		  tot_bw_r += mem_bw_gbps_r[i];
		}
	      VERBOSE(printf(") = %f GB/s\n", tot_bw_r););
	      mem_bw_table_r[n][mem_on] = tot_bw_r;

	      VERBOSE(printf("   WRITE BW ("););
	      for (int i = 0; i < n_threads; i++)
		{
		  VERBOSE(printf("+%2.2f", mem_bw_gbps_w[i]););
		  tot_bw_w += mem_bw_gbps_w[i];
		}
	      VERBOSE(printf(") = %f GB/s\n", tot_bw_w););
	      mem_bw_table_w[n][mem_on] = tot_bw_w;

	      NOT_VERBOSE(printf("\r# Progress : %6.1f%%", ++progress * progress_step); fflush(stdout););
	    }
	}
    }

  for (int n = 0; n < mctop_get_num_nodes(topo); n++)
    {
      numa_free((void*) mem_bw[n], test_mem_bw_size);
    }
  free(mem_bw);


  if (tid == 0)
    {
      NOT_VERBOSE(printf("\n"););
      free((void*) mem_bw_gbps_r);
      free((void*) mem_bw_gbps_w);
    }
  return NULL;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movslq (%rdi), %r13
movl 0x4(%rdi), %ebp
movq 0x18(%rdi), %r15
movq 0x20(%rdi), %r12
movq 0xd129(%rip), %r14      # 0x10220
movq %r12, %rdi
callq 0x7f33
leaq (,%rax,8), %rdi
callq 0x2b8e
movq %rax, 0x10(%rsp)
xorl %ebx, %ebx
movq %r12, %rdi
callq 0x7f33
cmpq %rbx, %rax
jbe 0x314d
movq 0xd0f9(%rip), %rdi      # 0x10220
movl %ebx, %esi
callq 0x21f0
movq 0x10(%rsp), %rcx
movq %rax, (%rcx,%rbx,8)
movq 0xd0e2(%rip), %rdx      # 0x10220
movq %rax, %rdi
xorl %esi, %esi
callq 0x2120
incq %rbx
jmp 0x3113
testl %r13d, %r13d
jne 0x3178
leaq (,%rbp,8), %rbx
movq %rbx, %rdi
callq 0x2b8e
movq %rax, 0xd16f(%rip)      # 0x102d8
movq %rbx, %rdi
callq 0x2b8e
movq %rax, 0xd168(%rip)      # 0x102e0
shrq $0x3, %r14
movl 0x18(%r12), %eax
imull %eax, %eax
cvtsi2sd %rax, %xmm1
movsd 0x6e77(%rip), %xmm0     # 0xa008
testl %r13d, %r13d
jne 0x31d4
movsd %xmm1, 0x18(%rsp)
cmpl $0x0, 0xd0e5(%rip)      # 0x10288
jne 0x31b7
leaq 0x71a0(%rip), %rdi      # 0xa34c
xorpd %xmm0, %xmm0
movb $0x1, %al
callq 0x2100
movq 0xce0a(%rip), %rax      # 0xffc8
movq (%rax), %rdi
callq 0x21e0
movsd 0x6e3a(%rip), %xmm0     # 0xa008
movsd 0x18(%rsp), %xmm1
movq %r12, 0x28(%rsp)
divsd %xmm1, %xmm0
movsd %xmm0, 0x30(%rsp)
movl %r14d, %r12d
xorl %ebx, %ebx
movq $0x0, 0x20(%rsp)
movq %r15, 0x18(%rsp)
movq 0x28(%rsp), %r14
movq %r14, %rdi
callq 0x7f33
cmpq %rbx, %rax
jbe 0x3588
movq %r14, %rdi
movq %rbx, (%rsp)
movq %rbx, %rsi
callq 0x83d6
cmpl $0x0, 0xd066(%rip)      # 0x10288
jne 0x3568
xorl %ebx, %ebx
movq 0x28(%rsp), %rdi
callq 0x7f33
cmpq %rbx, %rax
jbe 0x355c
cmpl $0x0, 0xd044(%rip)      # 0x10288
jne 0x348d
movq %r15, %rdi
callq 0x2090
testl %r13d, %r13d
jne 0x32cd
movl $0x6acfc0, %edi         # imm = 0x6ACFC0
movsd 0x6dac(%rip), %xmm0     # 0xa010
xorl %esi, %esi
callq 0x5684
movq 0x10(%rsp), %rax
movq (%rax,%rbx,8), %r14
movq %r14, %rdi
xorl %esi, %esi
movq %r12, %rdx
pushq $0x4
popq %rcx
callq 0x2f88
movq 0xd05d(%rip), %rax      # 0x102e8
movq %r13, %r15
movq %r12, %r13
movq (%rsp), %r12
movq (%rax,%r12,8), %rax
movsd %xmm0, (%rax,%rbx,8)
movq %r14, %rdi
pushq $0x1
popq %rsi
movq %r13, %rdx
pushq $0x4
popq %rcx
movq 0x18(%rsp), %r14
callq 0x2f88
movq 0xd035(%rip), %rax      # 0x102f0
movq (%rax,%r12,8), %rax
movq %r13, %r12
movq %r15, %r13
movq %r14, %r15
movsd %xmm0, (%rax,%rbx,8)
movq %r15, %rdi
callq 0x2090
movl $0x6acfc0, %edi         # imm = 0x6ACFC0
movsd 0x6d2e(%rip), %xmm0     # 0xa010
xorl %esi, %esi
callq 0x5684
lock
incl 0xcfcc(%rip)            # 0x102bc
movl 0xcfc6(%rip), %eax      # 0x102bc
cmpl %ebp, %eax
je 0x32fe
pause
jmp 0x32f0
movq 0x10(%rsp), %rax
movq (%rax,%rbx,8), %r14
movq %r14, %rdi
xorl %esi, %esi
movq %r12, %rdx
pushq $0x4
popq %r15
movq %r15, %rcx
callq 0x2f88
movq 0xcfb6(%rip), %rax      # 0x102d8
movsd %xmm0, (%rax,%r13,8)
movq %r14, %rdi
pushq $0x1
popq %rsi
movq %r12, %rdx
movq %r15, %rcx
movq 0x18(%rsp), %r15
callq 0x2f88
movq 0xcf9b(%rip), %rax      # 0x102e0
movsd %xmm0, (%rax,%r13,8)
movq %r15, %rdi
callq 0x2090
testl %r13d, %r13d
jne 0x3485
movl $0x0, 0xcf56(%rip)      # 0x102bc
cmpl $0x0, 0xcf1b(%rip)      # 0x10288
jne 0x34a3
xorpd %xmm0, %xmm0
xorl %r14d, %r14d
movq (%rsp), %rdx
movl 0xcf04(%rip), %ecx      # 0x10288
cmpq %r14, %rbp
je 0x33cc
movq 0xcf48(%rip), %rax      # 0x102d8
testl %ecx, %ecx
jne 0x339f
addsd (%rax,%r14,8), %xmm0
incq %r14
jmp 0x337e
movsd %xmm0, 0x8(%rsp)
movsd (%rax,%r14,8), %xmm0
leaq 0x6f77(%rip), %rdi      # 0xa329
movb $0x1, %al
callq 0x2100
movsd 0x8(%rsp), %xmm0
movq (%rsp), %rdx
movq 0xcf0e(%rip), %rax      # 0x102d8
jmp 0x3394
testl %ecx, %ecx
jne 0x34b6
movq 0xcf1d(%rip), %rax      # 0x102f8
movq (%rax,%rdx,8), %rax
movsd %xmm0, (%rax,%rbx,8)
xorpd %xmm0, %xmm0
xorl %r14d, %r14d
movl 0xce97(%rip), %ecx      # 0x10288
cmpq %r14, %rbp
je 0x3439
movq 0xcee3(%rip), %rax      # 0x102e0
testl %ecx, %ecx
jne 0x340c
addsd (%rax,%r14,8), %xmm0
incq %r14
jmp 0x33eb
movsd %xmm0, 0x8(%rsp)
movsd (%rax,%r14,8), %xmm0
leaq 0x6f0a(%rip), %rdi      # 0xa329
movb $0x1, %al
callq 0x2100
movsd 0x8(%rsp), %xmm0
movq (%rsp), %rdx
movq 0xcea9(%rip), %rax      # 0x102e0
jmp 0x3401
testl %ecx, %ecx
jne 0x3508
movq 0xceb8(%rip), %rax      # 0x10300
movq (%rax,%rdx,8), %rax
movsd %xmm0, (%rax,%rbx,8)
movq 0x20(%rsp), %rax
incl %eax
movq %rax, 0x20(%rsp)
cvtsi2sd %rax, %xmm0
mulsd 0x30(%rsp), %xmm0
leaq 0x6edc(%rip), %rdi      # 0xa34b
movb $0x1, %al
callq 0x2100
movq 0xcb4b(%rip), %rax      # 0xffc8
movq (%rax), %rdi
callq 0x21e0
incq %rbx
jmp 0x322a
testl %r13d, %r13d
je 0x3547
movq %r15, %rdi
callq 0x2090
jmp 0x32cd
leaq 0x6e71(%rip), %rdi      # 0xa31b
xorl %eax, %eax
callq 0x2100
jmp 0x3373
leaq 0x6e73(%rip), %rdi      # 0xa330
movsd %xmm0, 0x8(%rsp)
movb $0x1, %al
callq 0x2100
movq (%rsp), %rdx
cmpl $0x0, 0xcdb3(%rip)      # 0x10288
movq 0xce1c(%rip), %rax      # 0x102f8
movq (%rax,%rdx,8), %rax
movsd 0x8(%rsp), %xmm0
movsd %xmm0, (%rax,%rbx,8)
je 0x33e4
leaq 0x6e45(%rip), %rdi      # 0xa33d
xorl %eax, %eax
callq 0x2100
movq (%rsp), %rdx
jmp 0x33e4
leaq 0x6e21(%rip), %rdi      # 0xa330
movsd %xmm0, 0x8(%rsp)
movb $0x1, %al
movq %rdx, %r14
callq 0x2100
cmpl $0x0, 0xcd62(%rip)      # 0x10288
movq 0xcdd3(%rip), %rax      # 0x10300
movq (%rax,%r14,8), %rax
movsd 0x8(%rsp), %xmm0
movsd %xmm0, (%rax,%rbx,8)
je 0x3451
jmp 0x3485
leaq 0x6dba(%rip), %rdi      # 0xa308
movl %ebx, %esi
xorl %eax, %eax
callq 0x2100
jmp 0x324a
movq (%rsp), %rbx
incq %rbx
jmp 0x31f6
testl %r13d, %r13d
jne 0x3228
leaq 0x6d77(%rip), %rdi      # 0xa2ef
movq (%rsp), %rsi
xorl %eax, %eax
callq 0x2100
jmp 0x3228
xorl %ebx, %ebx
movq %r14, %rdi
callq 0x7f33
cmpq %rbx, %rax
jbe 0x35b1
movq 0x10(%rsp), %rax
movq (%rax,%rbx,8), %rdi
movq 0xcc79(%rip), %rsi      # 0x10220
callq 0x20c0
incq %rbx
jmp 0x358a
movq 0x10(%rsp), %rdi
callq 0x2030
testl %r13d, %r13d
jne 0x35e9
cmpl $0x0, 0xccc1(%rip)      # 0x10288
jne 0x35d1
pushq $0xa
popq %rdi
callq 0x2040
movq 0xcd00(%rip), %rdi      # 0x102d8
callq 0x2030
movq 0xccfc(%rip), %rdi      # 0x102e0
callq 0x2030
xorl %eax, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq