// File: /workspace/github_c_makefile_star2_O3/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
movl $0x4, %edi
callq 0x849f
movq %rax, 0x18(%rsp)
movq 0x10(%rax), %rbx
movl $0x1, 0x8(%rsp)
leaq 0x50(%rsp), %r14
leaq 0x2599(%rip), %r15      # 0xc029
leaq 0x14(%rsp), %rbp
xorl %r12d, %r12d
movq %r14, %rdi
leaq 0x2826(%rip), %rsi      # 0xc2c8
movl %r12d, %edx
xorl %eax, %eax
callq 0x22b0
movq %r14, %rdi
movq %r15, %rsi
callq 0x2240
testq %rax, %rax
je 0x9af3
movq %rax, %r13
movq %rax, %rdi
leaq 0x284e(%rip), %rsi      # 0xc317
movq %rbp, %rdx
xorl %eax, %eax
callq 0x2070
cmpl $0x1, %eax
jne 0x9b28
movl 0x14(%rsp), %eax
movq %rax, (%rbx,%r12,8)
movq %r13, %rdi
callq 0x20e0
incq %r12
cmpq $0x4, %r12
jne 0x9a98
jmp 0x9b4d
movq 0x64f6(%rip), %rax      # 0xfff0
movq (%rax), %rdi
movl $0x0, 0x8(%rsp)
leaq 0x27ec(%rip), %rsi      # 0xc2f8
movq %r14, %rdx
xorl %eax, %eax
callq 0x2170
incq %r12
cmpq $0x4, %r12
jne 0x9a98
jmp 0x9e74
movq 0x64c1(%rip), %rax      # 0xfff0
movq (%rax), %rdi
movl $0x0, 0x8(%rsp)
leaq 0x27da(%rip), %rsi      # 0xc31b
movq %r14, %rdx
xorl %eax, %eax
callq 0x2170
jmp 0x9ae0
cmpl $0x0, 0x8(%rsp)
je 0x9e74
movq 0x18(%rsp), %rbp
movq 0x18(%rbp), %rax
movq $0x4, (%rax)
movl $0x1, %ebx
movq 0x18(%rbp), %rax
movq -0x8(%rax,%rbx,8), %r8
shlq $0x2, %r8
movl $0x400, %eax            # imm = 0x400
cmpq %rax, %r8
cmovaeq %rax, %r8
movq 0x8(%rbp), %rax
movq 0x10(%rbp), %rcx
movsd -0x8(%rax,%rbx,8), %xmm0
unpcklps 0x4b5(%rip), %xmm0      # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x4bd(%rip), %xmm0      # 0xa060
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x2641(%rip), %xmm1     # 0xc1f8
movapd %xmm1, 0x20(%rsp)
subsd 0x47b(%rip), %xmm1      # 0xa040
movapd %xmm1, 0x40(%rsp)
movq (%rcx,%rbx,8), %rax
testq %rax, %rax
je 0x9c0f
movl $0xa, %r14d
movq %rax, %r15
cmpq %r8, %rax
jbe 0x9c09
movq %r8, %rcx
negq %rcx
movq %rax, %rdx
movq %rax, %r15
leaq -0xa(%r14), %rsi
subq %r8, %r15
incq %r14
cmpq $0x6, %rsi
ja 0x9c09
addq %rcx, %rdx
cmpq %r8, %rdx
movq %r15, %rdx
ja 0x9bee
leaq (%rax,%r8,8), %rcx
jmp 0x9c20
movq %rbx, %r14
shlq $0x5, %r14
movq %r8, %rcx
imulq %r14, %rcx
movq %r8, %r15
leaq 0x2618(%rip), %rdi      # 0xc23f
movq %rbx, 0x38(%rsp)
movl %ebx, %esi
movq %r15, %rdx
movq %rcx, %r12
movq %r8, 0x8(%rsp)
xorl %eax, %eax
callq 0x2100
movl $0x8, %esi
movq %r14, %rdi
callq 0x2150
testq %rax, %rax
je 0x9e9d
movq %rax, %r13
cvttsd2si 0x20(%rsp), %rax
movq %rax, %rcx
sarq $0x3f, %rcx
cvttsd2si 0x40(%rsp), %rbx
andq %rcx, %rbx
orq %rax, %rbx
movq $-0x1, %r14
cmpq %r12, %r15
movq %r12, 0x20(%rsp)
jae 0x9d6c
movq %r15, %rbp
xorl %r14d, %r14d
movq %rbp, %xmm0
punpckldq 0x3b4(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x3bc(%rip), %xmm0      # 0xa060
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x358(%rip), %xmm1      # 0xa010
mulsd 0x2540(%rip), %xmm1     # 0xc200
cvttsd2si %xmm1, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subsd 0x36c(%rip), %xmm1      # 0xa040
cvttsd2si %xmm1, %r12
andq %rcx, %r12
orq %rax, %r12
movl $0x40, %esi
leaq 0x50(%rsp), %rdi
movq %r12, %rdx
callq 0x22f0
testl %eax, %eax
jne 0x9e7e
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x9e7e
movq %r12, %rsi
callq 0x5c88
cmpq $0xf4241, %r12          # imm = 0xF4241
movl $0xf4240, %eax          # imm = 0xF4240
cmovbq %rax, %r12
movq 0x50(%rsp), %rdi
movq %r12, %rsi
callq 0x5c1c
movq %rax, %r12
movq 0x50(%rsp), %rdi
callq 0x2030
movq %r12, (%r13,%r14,8)
cmpq $0x2, %r14
jb 0x9d51
movq -0x8(%r13,%r14,8), %rax
addq %rbx, %rax
cmpq %rax, %r12
ja 0x9d64
incq %r14
addq 0x8(%rsp), %rbp
cmpq 0x20(%rsp), %rbp
jb 0x9c8f
decq %r14
movq 0x18(%rsp), %rbp
movq %r13, %rdi
addq $0x8, %rdi
movq %r14, %rsi
callq 0x5fbc
movq %rax, %r14
movq %rax, %rdi
movl %ebx, %esi
xorl %edx, %edx
callq 0x6258
movq %rax, %r12
movq %rax, %rdi
callq 0x657b
movq 0x20(%rsp), %rdx
cmpq %rdx, %r15
jae 0x9dd3
movq 0x8(%r12), %rax
movq 0x18(%rax), %rcx
xorl %eax, %eax
movq 0x8(%rsp), %rsi
cmpq %rcx, (%r13,%rax,8)
ja 0x9dc1
addq %rsi, %r15
incq %rax
cmpq %rdx, %r15
jb 0x9daf
decl %eax
subq %rsi, %r15
movq (%r13), %rdx
cmpl $0x2, %eax
jb 0x9dfc
cltq
jmp 0x9de3
subq 0x8(%rsp), %r15
movq (%r13), %rdx
movq $-0x1, %rax
movl $0x1, %ecx
movq (%r13,%rcx,8), %rsi
cmpq %rdx, %rsi
cmovbq %rsi, %rdx
incq %rcx
cmpq %rcx, %rax
jne 0x9de8
movq 0x8(%rbp), %rax
movq 0x38(%rsp), %rbx
movq %rdx, (%rax,%rbx,8)
movq 0x18(%rbp), %rax
movq %r15, (%rax,%rbx,8)
movq 0x10(%rbp), %rax
movq (%rax,%rbx,8), %rcx
leaq 0x245b(%rip), %rdi      # 0xc27b
movl %ebx, %esi
movq %r15, %r8
xorl %eax, %eax
callq 0x2100
movq %r12, %rdi
callq 0x64cd
movq %r14, %rdi
callq 0x61e4
movq %r13, %rdi
callq 0x2030
incq %rbx
cmpq $0x4, %rbx
jne 0x9b6d
movq 0x10(%rbp), %rax
movq 0x18(%rbp), %rcx
movq (%rax), %rax
movq %rax, (%rcx)
movq %rbp, %rax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x2a40
jmp 0x9b58
leaq 0x24b5(%rip), %rdi      # 0xc33a
leaq 0x24c6(%rip), %rsi      # 0xc352
leaq 0x24d1(%rip), %rcx      # 0xc364
movl $0x11, %edx
callq 0x2110
leaq 0x24a4(%rip), %rdi      # 0xc348
leaq 0xc54(%rip), %rsi       # 0xaaff
leaq 0xc82(%rip), %rcx       # 0xab34
movl $0x69, %edx
callq 0x2110