знание атрибутов кэша с помощью C

#c #caching

#c #кэширование

Вопрос:

У меня есть кэш черного ящика, и мне нужно найти ассоциативность и размер блока, написав программу на C.

Я запускаю свою программу на gcc и пытаюсь узнать ассоциативность для системного кэша. В моей программе я создал огромный массив и пытаюсь прочитать все элементы массива, что дает мне размер кэша.

 #include <stdio.h>
#include <stdlib.h>
#include <time.h>

void main()

{
  int array_1[250000], array_2[1000000], array_element;
  int i, j, n;
  clock_t start_1, end_1, start_2, end_2;
  float cpu_time_used, avg_time_per_elem;

  /* Fill the array with data  */
  for(i=0;i<250000;i  )
    array_1[i] = 123;
  for(i=0;i<500000;i  )
    array_2[i] = 123;

  /* To check data integrity  */
  printf("First Array element = %d n", array_1[0]);
  printf("Middle Array element = %d n", array_1[124999]);
  printf("Last Array element = %d n", array_1[249999]);

  /* Start measuring the clock cycles  */
  start_1 = clock();
  printf("n start = %dn", start_1);

for(i=0; i<1000;i  )   //number of iterations
  {
    for(j=0; j<250000; j  )  //number of elements
     {
         array_element = array_1[j];
     }
  }

  end_1 = clock();

  printf(" end = %dn n", end_1);
  cpu_time_used = end_1 - start_1;
  printf("CPU time used = %.10f ms n", cpu_time_used);
  cpu_time_used = cpu_time_used/CLOCKS_PER_SEC;
  printf("t      = %.6f seconds n", cpu_time_used);

  /* Calculating the average latency to access the data in cache */
  avg_time_per_elem = cpu_time_used/(i*j);
  printf("Average time to access one element = %.15f seconds = %.6f nanoseconds n n n", avg_time_per_elem, (avg_time_per_elem*1000000000));

  start_2 = clock();
  printf("n start = %dn", start_2);

for(i=0; i<2000;i  )   //number of iterations
  {
    for(j=0; j<1000000; j  )  //number of elements
     {
         array_element = array_2[j];
     }
  }

  end_2 = clock();

  printf(" end = %dn n", end_2);
  cpu_time_used = end_2 - start_2;
  printf("CPU time used = %.10f ms n", cpu_time_used);
  cpu_time_used = cpu_time_used/CLOCKS_PER_SEC;
  printf("t      = %.6f seconds n", cpu_time_used);

  /* Calculating the average latency to access the data in cache */
  avg_time_per_elem = cpu_time_used/(i*j);
  printf("Average time to access one element = %.15f seconds = %.6f nanoseconds n", avg_time_per_elem, (avg_time_per_elem*1000000000));

}
  

Таким образом, увеличивая размер массива при каждом запуске, я могу вычислить размер кэша L1 равным 32 КБ, т.е. в момент, когда время доступа резко возрастает. Но не могу понять, как найти ассоциативность и размер блока.

Комментарии:

1. В первой версии вопроса я думал, что это академическое упражнение, в котором «кэш черного ящика» каким-то образом отделен от собственного кэша процессора. Характеристика собственного кэша процессора кажется невыполнимой задачей.

2. Это действительно академическая задача. Я смог охарактеризовать время попадания и время пропуска кэша L1. Я искал онлайн-ресурсы, но все еще не могу найти возможный способ найти ассоциативность. Из команды>cpuid я вижу, что размер кэша для L1 равен 32 K. Но мне нужно проверить это с помощью моей программы.

3. При заданном ассоциативном кэше адреса, разделенные размером кэша (32 КБ), должны использовать один и тот же набор в кэше. Если кэш имеет двустороннюю ассоциативную привязку, то два адреса (например, 0x1000000 и 0x1008000) должны иметь хорошую производительность, но три адреса (0x1000000, 0x1008000, 0x1010000) не будут. Если кэш является 4-сторонним, то вам потребуется пять адресов, прежде чем производительность снизится, и так далее.

4. Однако проблема заключается в выборе адресов, которые в противном случае не используются. Например, если переменная i случайно использует тот же набор, что и два адреса, которые вы тестируете, то вы получите ужасную производительность в двустороннем кэше.

5. у @user3386109 есть ответ. Чтобы выбрать подходящую область, вам нужно взять адрес переменной стека, чтобы узнать, где находится ваш стек (поместите ваши рабочие переменные в структуру, чтобы вы знали выравнивание), а также адрес текущей функции. Затем либо выберите тот, который совпадает или не совпадает с вашими рабочими данными / кодом.