РЕДАКТИРОВАТЬ: Почему блок-ориентированный подход быстрее?Мы используем преимущества кэша данных процессора, гарантируя, что независимо от того, выполняем ли мы итерацию по блоку за строкой или по столбцу, мы гарантируем, что весь блок помещается в кэш.
Например, если у вас есть строка кэша32 байта и int
- 4 байта, вы можете разместить матрицу 8x8 int
в 8 строках кэша.Предполагая, что у вас достаточно большой кеш данных, вы можете выполнять итерацию по этой матрице либо по строке, либо по столбцу и быть уверенным, что кэш не будет перегружен.Еще один способ думать об этом - если ваша матрица помещается в кэш, вы можете перемещаться по ней любым нужным вам способом.
Если у вас матрица намного больше, например, 512x512, то вам нужно настроить матрицуобход такой, что вы не трогаете кеш.Например, если вы пересекаете матрицу в обратном порядке расположения матрицы, вы почти всегда будете пропускать кэш на каждом элементе, который вы посещаете.
Блочно-ориентированный подход гарантирует, что у вас будет только пропуск кэшадля данных, которые вы в конечном итоге посетите, прежде чем процессор очистит эту строку кэша.Другими словами, блочно-ориентированный подход, настроенный на размер строки кэша, гарантирует, что вы не перегрузите кэш.
Итак, если вы пытаетесь оптимизировать размер строки кэша компьютера, на котором вы работаетеВы можете перебирать матрицу в блочной форме и проверять каждый элемент матрицы только один раз:
int sum_diagonal_difference(int array[512][512], int block_size)
{
int i,j, block_i, block_j,result=0;
// sum diagonal blocks
for (block_i= 0; block_i<512; block_i+= block_size)
for (block_j= block_i + block_size; block_j<512; block_j+= block_size)
for(i=0; i<block_size; i++)
for(j=0; j<block_size; j++)
result+=abs(array[block_i + i][block_j + j]-array[block_j + j][block_i + i]);
result+= result;
// sum diagonal
for (int block_offset= 0; block_offset<512; block_offset+= block_size)
{
for (i= 0; i<block_size; ++i)
{
for (j= i+1; j<block_size; ++j)
{
int value= abs(array[block_offset + i][block_offset + j]-array[block_offset + j][block_offset + i]);
result+= value + value;
}
}
}
return result;
}
Вам следует поэкспериментировать с различными значениями для block_size
.На моей машине 8
приводит к наибольшему ускорению (в 2,5 раза) по сравнению с block_size
, равным 1 (и ~ 5x по сравнению с исходной итерацией по всей матрице).block_size
в идеале должно быть cache_line_size_in_bytes/sizeof(int)
.