LINUX.ORG.RU

Странное использование _mm_prefetch

 ,


1

1

Разбираю пример из статьи 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 байта, которое указано в начале программы?

Ответ на: комментарий от kto_tama

Так, я прочитал статью, но не нашел там ответа на вопрос о том, почему в _mm_prefetch передается такой адрес. Возможно я невнимательно читал? Единственное, что я вынес из статьи, что чаще всего процессор достаточно умен, чтобы работать без prefetch вообще, но это не отвечает на мой вопрос.

Goganchic ★★
() автор топика

Моё понимание (без детального анализа кода):

  • в одну кеш-линию (64 байта) влазит 8 double
  • элементы матрицы обрабатываются по 8 штук за раз, т.е. работа идет с одной кеш-линией
  • rmul1[8] - это начало следующих восьми элементов, которые нужно загрузить в кеш, пока мы обрабатываем текущие 8 элементов в одной кеш-линии, начинающиеся по адресу rmul1[0].
blex ★★
()