Я прочитал статью из блога Игоря . В статье сказано:
... современные процессоры не обращаются к памяти побайтно. Вместо этого они извлекают память кусками (обычно) 64 байта, называемыми строками кэша. Когда вы читаете определенную ячейку памяти, вся строка кэша извлекается из основной памяти в кеш. И доступ к другим значениям из той же строки кэша обходится дешево!
В статье также приведен код на c # для проверки вышеприведенного вывода:
int[] arr = new int[64 * 1024 * 1024];
// Loop 1 (step = 1)
for (int i = 0; i < arr.Length; i++) arr[i] *= 3;
// Loop 2 (step = 16)
for (int i = 0; i < arr.Length; i += 16) arr[i] *= 3;
Два цикла for занимают околов то же время: 80 и 78 мс соответственно на машине Игоря, поэтому проверяется механизм строки кэша.
И затем я отсылаю вышеупомянутую идею к реализации версии c ++ для проверки размера строки кэша следующим образом:
#include "stdafx.h"
#include <iostream>
#include <chrono>
#include <math.h>
using namespace std::chrono;
const int total_buff_count = 16;
const int buff_size = 32 * 1024 * 1024;
int testCacheHit(int * pBuffer, int size, int step)
{
int result = 0;
for (int i = 0; i < size;) {
result += pBuffer[i];
i += step;
}
return result;
}
int main()
{
int * pBuffer = new int[buff_size*total_buff_count];
for (int i = 0; i < total_buff_count; ++i) {
int step = (int)pow(2, i);
auto start = std::chrono::system_clock::now();
volatile int result = testCacheHit(pBuffer + buff_size*i, buff_size, step);
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << "step: " << step << ", elapsed time: " << elapsed_seconds.count() * 1000 << "ms\n";
}
delete[] pBuffer;
}
Но мой результат теста совершенно не такой, как в статье Игоря. Если шаг равен 1, тогда временные затраты составляют около 114 мс;Если шаг равен 16, то стоимость времени составляет около 78 мс. Тестовое приложение построено с конфигурацией выпуска, на моей машине 32 ГБ памяти, а процессор - Intel Xeon E5 2420 v2 2.2G;результат следующий.
Интересным выводом является то, что затраты времени значительно уменьшились, когда шаг 2 и шаг 2048. Мой вопрос заключается в том, как объяснить разрыв, когда шаг 2 и шаг 2048в моем тесте? И как проверить размер строки кэша процессора с кодом C ++? Почему мой результат полностью отличается от результата Игоря? Спасибо.
Мое собственное объяснение первого вопроса состоит в том, что временная стоимость кода состоит из двух частей: одна - «чтение / запись памяти», которая содержит стоимость чтения / записи памяти, другая - «другие затраты». который содержит для цикла и расчета стоимости. Если шаг равен 2, то стоимость «чтения / записи в память» почти не изменяется (из-за строки кэша), но стоимость вычислений и циклов сократилась вдвое, поэтому мы видим очевидный разрыв. И я предполагаю, что строка кэша на моем процессоре составляет 4096 байтов (1024 * 4 байта), а не 64 байта, поэтому мы получили еще один разрыв, когда шаг 2048. Но это только мое предположение. Спасибо за любую помощь от ваших парней.