// File: /workspace/github_c_makefile_star2_O2/LPD-EPFL[P]mctop/src/mctop_cache.c
// Function: mctop_cache_size_estimate
mctop_cache_info_t*
mctop_cache_size_estimate()
{
  /* +1 level for 0: i cache */
  mctop_cache_info_t* mci = mctop_cache_info_create(mctop_cache_n_lvls + 1);

  int sizes_OS_ok = mctop_cache_size_read_OS(mci->sizes_OS);
  if (!sizes_OS_ok)
    {
      fprintf(stderr, "MCTOP Warning: Can't read cache sizes from OS\n");
    }

  const size_t KB = 1024;
  
  mci->sizes_estimated[0] = 4;

  const size_t n_steps_fix = 32;
      

  for (int lvl = 1; lvl <= mctop_cache_n_lvls; lvl++)
    {
      size_t n_steps = (lvl * n_steps_fix);
      size_t stp = 4 * mci->sizes_estimated[lvl - 1];
      if (stp > 1024)
	{
	  stp = 1024;
	}
      size_t sensitivity = 1.2 * mci->latencies[lvl - 1];
      int64_t min = stp;
      size_t max = n_steps * stp;

      size_t size_OS = mci->sizes_OS[lvl];
      if (size_OS > 0)
	{
	  const size_t n_steps_side = 8;
	  min = size_OS;
	  n_steps = 0;
	  while (n_steps++ < n_steps_side && min > stp)
	    {
	      min -= stp;
	    }
	  max = size_OS + (n_steps_side * stp);
	  n_steps += n_steps_side + 1;
	}


      printf("## Looking for L%d cache size (%zu to %zu KB, step %zu KB)\n",
	     lvl, min, max, stp);

      ticks* lat = calloc_assert(n_steps, sizeof(ticks));

      size_t n = 0, kb;
      for (kb = min; kb < max; kb += stp)
	{
	  lat[n] = ll_random_latency(((kb * 0.98) * KB));

	  //	  printf("[%2zu[ %-5zu KB -> %-5zu cycles\n", n, kb, lat[n]);
	  if (n > 1 && lat[n] > (lat[n - 1] +  sensitivity))
	    {
	      break;
	    }
	  n++;
	}

      cdf_t* cdf = cdf_calc(lat + 1, n - 1);
      //      cdf_t* cdf = cdf_calc(lat, n);
      /* cdf_print(cdf); */
      cdf_cluster_t* cc = cdf_cluster(cdf, sensitivity, 0);
      cdf_cluster_print(cc);

      size_t tlat = cc->clusters[0].val_max;

      for (kb = min, n = 0; kb < max && lat[n] <= tlat; kb += stp, n++);
      kb -= stp;
    
      size_t clat = array_get_min(lat, n - 1);

      mci->latencies[lvl] = clat;
      mci->sizes_estimated[lvl] = kb;

      printf("## Cache L%d / Latency: %-4zu / Size:    OS: %5zu KB     Estimated: %5zu KB\n",
	     lvl, clat, mci->sizes_OS[lvl], mci->sizes_estimated[lvl]);

      cdf_cluster_free(cc);
      cdf_free(cdf);

      free(lat);
    }

  mci->sizes_estimated[0] = mci->sizes_OS[0];

  return mci;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
pushq $0x4
popq %rdi
callq 0x78f7
movq %rax, 0x18(%rsp)
movq 0x10(%rax), %rbp
pushq $0x1
popq %rax
movl %eax, 0x8(%rsp)
leaq 0x3474(%rip), %rbx      # 0xc2c8
leaq 0x50(%rsp), %r14
leaq 0x31c9(%rip), %r15      # 0xc029
xorl %r12d, %r12d
cmpq $0x4, %r12
je 0x8f0b
movq %r14, %rdi
movq %rbx, %rsi
movl %r12d, %edx
xorl %eax, %eax
callq 0x22b0
movq %r14, %rdi
movq %r15, %rsi
callq 0x2240
testq %rax, %rax
je 0x8ec1
movq %rax, %r13
movq %rax, %rdi
leaq 0x347d(%rip), %rsi      # 0xc317
leaq 0x14(%rsp), %rdx
xorl %eax, %eax
callq 0x2070
cmpl $0x1, %eax
jne 0x8ee6
movl 0x14(%rsp), %eax
movq %rax, (%rbp,%r12,8)
movq %r13, %rdi
callq 0x20e0
incq %r12
jmp 0x8e63
movq 0x7128(%rip), %rax      # 0xfff0
movq (%rax), %rdi
movl $0x0, 0x8(%rsp)
leaq 0x341e(%rip), %rsi      # 0xc2f8
movq %r14, %rdx
xorl %eax, %eax
callq 0x2170
jmp 0x8ebc
movq 0x7103(%rip), %rax      # 0xfff0
movq (%rax), %rdi
movl $0x0, 0x8(%rsp)
leaq 0x341c(%rip), %rsi      # 0xc31b
movq %r14, %rdx
xorl %eax, %eax
callq 0x2170
jmp 0x8eb4
cmpl $0x0, 0x8(%rsp)
je 0x91ed
movq 0x18(%rsp), %r12
movq 0x18(%r12), %rax
movq $0x4, (%rax)
pushq $0x1
popq %rsi
cmpq $0x4, %rsi
je 0x91c8
movq 0x18(%r12), %rax
movq -0x8(%rax,%rsi,8), %r13
shlq $0x2, %r13
movl $0x400, %eax            # imm = 0x400
cmpq %rax, %r13
cmovaeq %rax, %r13
movq 0x8(%r12), %rax
movq 0x10(%r12), %rcx
movsd -0x8(%rax,%rsi,8), %xmm0
unpcklps 0x10eb(%rip), %xmm0     # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x10f3(%rip), %xmm0     # 0xa060
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x3277(%rip), %xmm1     # 0xc1f8
movapd %xmm1, %xmm0
subsd 0x10b3(%rip), %xmm0     # 0xa040
movq (%rcx,%rsi,8), %rax
testq %rax, %rax
movapd %xmm1, 0x20(%rsp)
movapd %xmm0, 0x40(%rsp)
je 0x8fc8
pushq $0xa
popq %rbx
movq %rax, %r15
leaq -0xa(%rbx), %rcx
cmpq $0x7, %rcx
ja 0x8fc2
movq %r15, %rcx
subq %r13, %rcx
jbe 0x8fc2
incq %rbx
movq %rcx, %r15
jmp 0x8fa8
leaq (%rax,%r13,8), %rcx
jmp 0x8fd9
movq %rsi, %rbx
shlq $0x5, %rbx
movq %r13, %rcx
imulq %rbx, %rcx
movq %r13, %r15
leaq 0x325f(%rip), %rdi      # 0xc23f
movq %rsi, 0x38(%rsp)
movq %r15, %rdx
movq %rcx, 0x8(%rsp)
movq %r13, %r8
xorl %eax, %eax
callq 0x2100
movq %rbx, %rdi
pushq $0x8
popq %rsi
callq 0x2150
testq %rax, %rax
je 0x922b
movq %rax, %rbx
cvttsd2si 0x20(%rsp), %rax
movq %rax, %rcx
sarq $0x3f, %rcx
cvttsd2si 0x40(%rsp), %rdx
andq %rcx, %rdx
orq %rax, %rdx
movq %rdx, 0x20(%rsp)
xorl %r14d, %r14d
movq %r15, %r12
cmpq 0x8(%rsp), %r12
jae 0x910b
movq %r12, %xmm0
punpckldq 0x1004(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x100c(%rip), %xmm0     # 0xa060
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0xfa8(%rip), %xmm1      # 0xa010
mulsd 0x3190(%rip), %xmm1     # 0xc200
cvttsd2si %xmm1, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subsd 0xfbc(%rip), %xmm1      # 0xa040
cvttsd2si %xmm1, %rbp
andq %rcx, %rbp
orq %rax, %rbp
leaq 0x50(%rsp), %rdi
pushq $0x40
popq %rsi
movq %rbp, %rdx
callq 0x22f0
testl %eax, %eax
jne 0x920e
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x920e
movq %rbp, %rsi
callq 0x5559
cmpq $0xf4241, %rbp          # imm = 0xF4241
movl $0xf4240, %eax          # imm = 0xF4240
cmovbq %rax, %rbp
movq 0x50(%rsp), %rdi
movq %rbp, %rsi
callq 0x54f1
movq %rax, %rbp
movq 0x50(%rsp), %rdi
callq 0x2030
movq %rbp, (%rbx,%r14,8)
cmpq $0x2, %r14
jb 0x9100
movq -0x8(%rbx,%r14,8), %rax
addq 0x20(%rsp), %rax
cmpq %rax, %rbp
ja 0x910b
incq %r14
addq %r13, %r12
jmp 0x9034
movq %rbx, %rdi
addq $0x8, %rdi
decq %r14
movq %r14, %rsi
callq 0x5880
movq %rax, %r14
movq %rax, %rdi
movq 0x20(%rsp), %rsi
xorl %edx, %edx
callq 0x5ae4
movq %rax, %rbp
movq %rax, %rdi
callq 0x5dae
movq 0x8(%rbp), %rax
movq 0x18(%rax), %rax
xorl %esi, %esi
movq 0x18(%rsp), %r12
movq 0x8(%rsp), %rcx
cmpq %rcx, %r15
jae 0x9161
cmpq %rax, (%rbx,%rsi,8)
ja 0x9161
addq %r13, %r15
incq %rsi
jmp 0x914e
subq %r13, %r15
decl %esi
movq %rbx, %rdi
callq 0x9244
movq 0x8(%r12), %rcx
movq 0x38(%rsp), %r13
movq %rax, (%rcx,%r13,8)
movq 0x18(%r12), %rcx
movq %r15, (%rcx,%r13,8)
movq 0x10(%r12), %rcx
movq (%rcx,%r13,8), %rcx
leaq 0x30e6(%rip), %rdi      # 0xc27b
movl %r13d, %esi
movq %rax, %rdx
movq %r15, %r8
xorl %eax, %eax
callq 0x2100
movq %rbp, %rdi
callq 0x5d08
movq %r14, %rdi
callq 0x5a76
movq %rbx, %rdi
callq 0x2030
movq %r13, %rsi
incq %rsi
jmp 0x8f2a
movq 0x10(%r12), %rax
movq 0x18(%r12), %rcx
movq (%rax), %rax
movq %rax, (%rcx)
movq %r12, %rax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x6dfc(%rip), %rax      # 0xfff0
movq (%rax), %rcx
leaq 0x3012(%rip), %rdi      # 0xc210
pushq $0x2e
popq %rsi
pushq $0x1
popq %rdx
callq 0x22d0
jmp 0x8f16
leaq 0x3125(%rip), %rdi      # 0xc33a
leaq 0x3136(%rip), %rsi      # 0xc352
leaq 0x3141(%rip), %rcx      # 0xc364
pushq $0x11
popq %rdx
callq 0x2110
leaq 0x3116(%rip), %rdi      # 0xc348
leaq 0x18c6(%rip), %rsi      # 0xaaff
leaq 0x18f4(%rip), %rcx      # 0xab34
pushq $0x69
jmp 0x9225