// File: /workspace/github_c_makefile_star2_O1/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 $0xa8, %rsp
movl $0x4, %edi
callq 0x8536
movq %rax, 0x10(%rsp)
movq 0x10(%rax), %rbx
movl $0x1, 0x8(%rsp)
leaq 0x40(%rsp), %r14
leaq 0x3411(%rip), %r15      # 0xd029
leaq 0x1c(%rsp), %rbp
xorl %r12d, %r12d
movq %r14, %rdi
leaq 0x369e(%rip), %rsi      # 0xd2c8
movl %r12d, %edx
xorl %eax, %eax
callq 0x22b0
movq %r14, %rdi
movq %r15, %rsi
callq 0x2240
testq %rax, %rax
je 0x9c7b
movq %rax, %r13
movq %rax, %rdi
leaq 0x36c6(%rip), %rsi      # 0xd317
movq %rbp, %rdx
xorl %eax, %eax
callq 0x2070
cmpl $0x1, %eax
jne 0x9ca0
movl 0x1c(%rsp), %eax
movq %rax, (%rbx,%r12,8)
movq %r13, %rdi
callq 0x20e0
incq %r12
cmpq $0x4, %r12
jne 0x9c20
jmp 0x9cc5
movq 0x736e(%rip), %rax      # 0x10ff0
movq (%rax), %rdi
movl $0x0, 0x8(%rsp)
leaq 0x3664(%rip), %rsi      # 0xd2f8
movq %r14, %rdx
xorl %eax, %eax
callq 0x2170
jmp 0x9c70
movq 0x7349(%rip), %rax      # 0x10ff0
movq (%rax), %rdi
movl $0x0, 0x8(%rsp)
leaq 0x3662(%rip), %rsi      # 0xd31b
movq %r14, %rdx
xorl %eax, %eax
callq 0x2170
jmp 0x9c68
cmpl $0x0, 0x8(%rsp)
je 0x9fee
movq 0x10(%rsp), %rbx
movq 0x18(%rbx), %rax
movq $0x4, (%rax)
movl $0x1, %ebp
movq 0x18(%rbx), %rax
movq -0x8(%rax,%rbp,8), %r8
shlq $0x2, %r8
movl $0x400, %eax            # imm = 0x400
cmpq %rax, %r8
cmovaeq %rax, %r8
movq 0x8(%rbx), %rax
movq 0x10(%rbx), %rcx
movsd -0x8(%rax,%rbp,8), %xmm0
unpcklps 0x133d(%rip), %xmm0     # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1345(%rip), %xmm0     # 0xb060
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x34c9(%rip), %xmm1     # 0xd1f8
movapd %xmm1, 0x30(%rsp)
subsd 0x1303(%rip), %xmm1     # 0xb040
movapd %xmm1, 0x20(%rsp)
movq (%rcx,%rbp,8), %rax
testq %rax, %rax
je 0x9d87
movl $0xa, %r14d
movq %rax, %r15
cmpq %r8, %rax
jbe 0x9d81
movq %r8, %rcx
negq %rcx
movq %rax, %rdx
movq %rax, %r15
leaq -0xa(%r14), %rsi
subq %r8, %r15
incq %r14
cmpq $0x6, %rsi
ja 0x9d81
addq %rcx, %rdx
cmpq %r8, %rdx
movq %r15, %rdx
ja 0x9d66
leaq (%rax,%r8,8), %r12
jmp 0x9d98
movq %rbp, %r14
shlq $0x5, %r14
movq %r8, %r12
imulq %r14, %r12
movq %r8, %r15
leaq 0x34a0(%rip), %rdi      # 0xd23f
movl %ebp, %esi
movq %r15, %rdx
movq %r12, %rcx
movq %r8, 0x8(%rsp)
xorl %eax, %eax
callq 0x2100
movl $0x8, %esi
movq %r14, %rdi
callq 0x2150
testq %rax, %rax
je 0xa017
movq %rax, %r13
cvttsd2si 0x30(%rsp), %rax
movq %rax, %rcx
sarq $0x3f, %rcx
cvttsd2si 0x20(%rsp), %rbx
andq %rcx, %rbx
orq %rax, %rbx
movq $-0x1, %r14
cmpq %r12, %r15
movq %r12, 0x30(%rsp)
jae 0x9ee4
movq %rbp, 0x20(%rsp)
movq %r15, %rbp
xorl %r14d, %r14d
movq %rbp, %xmm0
punpckldq 0x123c(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1244(%rip), %xmm0     # 0xb060
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x11e0(%rip), %xmm1     # 0xb010
mulsd 0x33c8(%rip), %xmm1     # 0xd200
cvttsd2si %xmm1, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subsd 0x11f4(%rip), %xmm1     # 0xb040
cvttsd2si %xmm1, %r12
andq %rcx, %r12
orq %rax, %r12
movl $0x40, %esi
leaq 0x40(%rsp), %rdi
movq %r12, %rdx
callq 0x22f0
testl %eax, %eax
jne 0x9ff8
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x9ff8
movq %r12, %rsi
callq 0x5cac
cmpq $0xf4241, %r12          # imm = 0xF4241
movl $0xf4240, %eax          # imm = 0xF4240
cmovbq %rax, %r12
movq 0x40(%rsp), %rdi
movq %r12, %rsi
callq 0x5c40
movq %rax, %r12
movq 0x40(%rsp), %rdi
callq 0x2030
movq %r12, (%r13,%r14,8)
cmpq $0x2, %r14
jb 0x9ec9
movq -0x8(%r13,%r14,8), %rax
addq %rbx, %rax
cmpq %rax, %r12
ja 0x9edc
incq %r14
addq 0x8(%rsp), %rbp
cmpq 0x30(%rsp), %rbp
jb 0x9e07
decq %r14
movq 0x20(%rsp), %rbp
movq %r13, %rdi
addq $0x8, %rdi
movq %r14, %rsi
callq 0x6020
movq %rax, 0x20(%rsp)
movq %rax, %rdi
movl %ebx, %esi
xorl %edx, %edx
callq 0x62bc
movq %rax, %r14
movq %rax, %rdi
callq 0x65f8
movq 0x30(%rsp), %rdx
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpq %rdx, %r15
jae 0x9f48
movq 0x8(%r14), %rax
movq 0x18(%rax), %rcx
xorl %eax, %eax
movq 0x8(%rsp), %rdi
movq 0x10(%rsp), %rbx
cmpq %rcx, (%r13,%rax,8)
ja 0x9f44
addq %rdi, %r15
incq %rax
cmpq %rdx, %r15
jb 0x9f32
decl %eax
jmp 0x9f52
movq 0x8(%rsp), %rdi
movq 0x10(%rsp), %rbx
movq (%r13), %rdx
cmpl $0x2, %eax
jb 0x9f76
cltq
movl $0x1, %ecx
movq (%r13,%rcx,8), %rsi
cmpq %rdx, %rsi
cmovbq %rsi, %rdx
incq %rcx
cmpq %rcx, %rax
jne 0x9f62
subq %rdi, %r15
movq 0x8(%rbx), %rax
movq %rdx, (%rax,%rbp,8)
movq 0x18(%rbx), %rax
movq %r15, (%rax,%rbp,8)
movq 0x10(%rbx), %rax
movq (%rax,%rbp,8), %rcx
leaq 0x32e3(%rip), %rdi      # 0xd27b
movl %ebp, %esi
movq %r15, %r8
xorl %eax, %eax
callq 0x2100
movq %r14, %rdi
callq 0x6558
movq 0x20(%rsp), %rdi
callq 0x6248
movq %r13, %rdi
callq 0x2030
incq %rbp
cmpq $0x4, %rbp
jne 0x9ce5
movq 0x10(%rbx), %rax
movq 0x18(%rbx), %rcx
movq (%rax), %rax
movq %rax, (%rcx)
movq %rbx, %rax
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x2a22
jmp 0x9cd0
leaq 0x333b(%rip), %rdi      # 0xd33a
leaq 0x334c(%rip), %rsi      # 0xd352
leaq 0x3357(%rip), %rcx      # 0xd364
movl $0x11, %edx
callq 0x2110
leaq 0x332a(%rip), %rdi      # 0xd348
leaq 0x1ada(%rip), %rsi      # 0xbaff
leaq 0x1b08(%rip), %rcx      # 0xbb34
movl $0x69, %edx
callq 0x2110