Странное использование _mm_prefetch
Разбираю пример из статьи What Every Programmer Should Know About Memory про векторные оптимизации при умножении матриц:
#include <stdlib.h>
#include <stdio.h>
#include <emmintrin.h>
#define N 1000
double res[N][N] __attribute__ ((aligned (64)));
double mul1[N][N] __attribute__ ((aligned (64)));
double mul2[N][N] __attribute__ ((aligned (64)));
#define SM (CLS / sizeof (double))
int
main (void)
{
// ... Initialize mul1 and mul2
int i, i2, j, j2, k, k2;
double *restrict rres;
double *restrict rmul1;
double *restrict rmul2;
for (i = 0; i < N; i += SM)
for (j = 0; j < N; j += SM)
for (k = 0; k < N; k += SM)
for (i2 = 0, rres = &res[i][j], rmul1 = &mul1[i][k]; i2 < SM; ++i2, rres += N, rmul1 += N)
{
_mm_prefetch (&rmul1[8], _MM_HINT_NTA);
for (k2 = 0, rmul2 = &mul2[k][j]; k2 < SM; ++k2, rmul2 += N)
{
__m128d m1d = _mm_load_sd (&rmul1[k2]);
m1d = _mm_unpacklo_pd (m1d, m1d);
for (j2 = 0; j2 < SM; j2 += 2)
{
__m128d m2 = _mm_load_pd (&rmul2[j2]);
__m128d r2 = _mm_load_pd (&rres[j2]);
_mm_store_pd (&rres[j2], _mm_add_pd (_mm_mul_pd (m2, m1d), r2));
}
}
}
// ... use res matrix
return 0;
}
Не до конца понимаю идею с _mm_prefetch
. Как я прочитал из документации _mm_prefetch
позволяет подсказать процессору как кешировать те или иные данные. Поскольку мы итерируемся блоками по SM
элементов, то очевидно, что пытаться закешировать элемент, следующий за rmul1
не имеет смысла, т.к. использовать мы его все равно не будем, а попытка кеширования сбросит полезные кеши для других элементов. Поэтому мы помечаем элемент как Non-Temporal Data. Вопрос в том, почему мы помечаем адрес &rmul1[8]
? Т.е. мы берем адрес 8-го double-элемента в rmul1 и помечаем его как Non-Temporal. Не понимаю почему именно 8го. Может быть это как-то связано с выравниванием по 64 байта, которое указано в начале программы?