Нижегородский государственный университет им. Н.И.Лобачевского
Опубликован: 30.05.2014 | Доступ: свободный | Студентов: 302 / 35 | Длительность: 11:26:00

Самостоятельная работа 5: Оптимизация вычислений в задаче матричного умножения. Оптимизация работы с памятью

Векторизация вычислений

Существенная влияние на производительность программ на Intel Xeon Phi оказывает применении векторных инструкций сопроцессора. Если производительность алгоритма недостаточно высокая, полезно проверить, смог ли компилятор "векторизовать" код.

Проверим, векторизован ли внутренний цикл в алгоритме умножения матриц. Для этого соберем отчет о векторизации, добавив ключ компиляции:

icpc -mmic -mkl -openmp -vec-report3 ./single.cpp ./mainBlock.cpp ./routine.cpp -osingle

Результат отчета:

./single.cpp(8): (col. 5) remark: loop was not vectorized: loop was transformed to memset or memcpy
./single.cpp(7): (col. 3) remark: loop was not vectorized: not inner loop
./single.cpp(14): (col. 7) remark: LOOP WAS VECTORIZED
./single.cpp(14): (col. 7) remark: PEEL LOOP WAS VECTORIZED
./single.cpp(14): (col. 7) remark: REMAINDER LOOP WAS VECTORIZED
./single.cpp(14): (col. 7) remark: loop skipped: multiversioned
./single.cpp(13): (col. 5) remark: loop was not vectorized: not inner loop
./single.cpp(12): (col. 3) remark: loop was not vectorized: not inner loop

Из отчета видно, что внутренний цикл векторизован. При этом компилятор создал несколько версий кода. Как минимум создана версия, использующая векторные инструкции и аналогичная скалярная версия. Компилятор заранее не знает размеров матрицы. Также учитывая, что матрицы передаются в функцию как указатель на массив, массивы теоретически могут пересекаться. Как следствие, компилятор обязан предположить, что реализацию алгоритма векторизовать нельзя. Для того, что бы помочь компилятору векторизовать код и не порождать лишних версий, можно использовать директивы simd, ivdep или ключевое слово restrict [12.7, 12.8]. В рамках данной лабораторной работы ограничимся использованием директивы simd.

Применим директиву simd к внутреннему циклу.

void mult(ELEMENT_TYPE * A, ELEMENT_TYPE * B, 
          ELEMENT_TYPE * C, int n)
{
  ELEMENT_TYPE s;
  int i, j, k;
  for(j = 0; j < n; j++ )
    for(i = 0; i < n; i++ )  
      C[j * n + i] = 0;
  
  
  for(j = 0; j < n; j++ )
    for(k = 0; k < n; k++ )
#pragma simd
      for(i = 0; i < n; i++ )
        C[j * n + i] += A[j * n + k] * B[k * n + i];
}
Еще раз соберем отчет о векторизации.
./single.cpp(7): (col. 3) remark: loop was not vectorized: not inner loop
./single.cpp(15): (col. 7) remark: SIMD LOOP WAS VECTORIZED
./single.cpp(15): (col. 7) remark: PEEL LOOP WAS VECTORIZED
./single.cpp(15): (col. 7) remark: REMAINDER LOOP WAS VECTORIZED
./single.cpp(13): (col. 5) remark: loop was not vectorized: not inner loop
./single.cpp(12): (col. 3) remark: loop was not vectorized: not inner loop

Из отчета видно, что осталась только векторная ветка кода.

Стоит также отметить, что для векторизации важно, что бы данные были выровнены по границе 64 байт. Если данные не выровнены, то цикл разбивается на три части. Первая часть – часть до первого выровненного элемента. Вторая часть – основная часть цикла, векторизованная. Третья часть – "хвост" цикла. Наличие подобного разделения цикла может снизить производительность. Для оптимизации выполнения программ можно воспользоваться специальной функцией выделения памяти с выравниванием __mm_malloc. Ниже приведен код выделения и освобождения памяти для матриц:

#include <immintrin.h> 
…
void allocMatrix(ELEMENT_TYPE ** mat, int n)
{
  // выделяем память, выровненную по 64 байт
  (*mat) = (ELEMENT_TYPE *)_mm_malloc(sizeof(ELEMENT_TYPE)*
                                      (n * n), 64);
}
void freeMatrix(ELEMENT_TYPE ** mat)
{
  _mm_free((*mat));
}

Из таблицы 10.6 видно, что за счет выравнивания памяти и помощи компилятору путем применения директив удалось получить чуть лучшую реализацию алгоритма. Соберите отчет о векторизации и проверьте, что компилятор больше не создает "пролог" для цикла.

Таблица 10.6. Время работы алгоритма умножения матриц при добавлении директивы simd и выравнивании памяти на Intel Xeon Phi (время в секундах).
N jki jki + simd + _mm_malloc
1024 2,085 1,912
2048 15,929 15,126
3072 52,934 50,816
Svetlana Svetlana
Svetlana Svetlana

Здравствуйие! Я хочу пройти курс Введение в принципы функционирования и применения современных мультиядерных архитектур (на примере Intel Xeon Phi), в презентации самостоятельной работы №1 указаны логин и пароль для доступ на кластер и выполнения самостоятельных работ, но войти по такой паре логин-пароль не получается. Как предполагается выполнение самосоятельных работ в этом курсе?