Опубликован: 11.10.2012 | Доступ: свободный | Студентов: 307 / 58 | Длительность: 07:36:00
Лекция 1:

Компиляторы Intel. Возможности автоматической оптимизации

Лекция 1: 1234 || Лекция 2 >

Векторизация

Векторные команды (SIMD)


AVX – набор векторных команд

Intel® AVX (Advanced Vector Extensions) расширяет возможности 128-разрядных векторных регистров XMM (16 регистров), позволяя использовать 256-разрядные векторы. 256 разрядов используются в операциях с плавающей точкой.

В других операциях используются младшие 128 разрядов.

В AVX операнды и результат операции отделены друг от друга. Это позволяет оптимизировать использование регистров, генерировать более компактный код, уменьшить количество зависимостей т.д.

AVX для архитектуры Sandy Bridge


Поддержка векторных конструкций в Intel® CilkTM Plus и Array Building Blocks.

Поддержка прагм и "интринсиков" (низкоуровневые возможности).

Поддержка сложных условных выражений.

Улучшенная поддержка смешения типов в одном цикле.

Поддержка операций с насыщением.

Отчёты об оптимизации

Отчёты об оптимизации

  • /Qvec-report - генерация протокола векторизации (что векторизовано, что нет и почему).
  • /Qpar-report - генерация протокола распараллеливания.
  • /Qopt-report - генерация протокола оптимизации.

Профилирование на уровне циклов

Сбор статистики по циклам и функциям

  • /Qprofile-loops:all - сбор статистики.
  • LoopProfileViewer - утилита для просмотра отчётов.
  • GAP - Guided Auto Parallelism (направляемая автопараллелизация).
  • /Qguide (-guide) - запуск анализа.
  • Не порождает параллельный код, но даёт рекомендации.

Оптимизация в примерах

/Od (Windows), -O0 (Linux)

  • Отключение оптимизации
  • Подразумевается в режиме Debug в MS Visual Studio

/O1 (Windows), -O1 (Linux)

  • Глобальная оптимизация
  • Не увеличивает размер кода

/O2 (Windows), -O2 (Linux)

  • Увеличивает размер кода
  • Оптимизация времени выполнения
  • Опция по умолчанию
  • Подстановки в коде
  • Развертывание циклов
  • Векторизация

/O3 (Windows), -O3 (Linux)

  • Высокоуровневая оптимизация.
  • Оптимизирующие преобразования уровня /O2 + более агрессивные методы.
  • Улучшенная векторизация.
  • Более полный учёт свойств циклов и массивов.
  • Оптимизация циклов: разделение циклов (loop distribution), перестановка циклов (loop interchange), слияние циклов (loop fusion), развёртка циклов (loop unrolling).
  • Подстановка кода в ветвлениях.
  • Оптимизация под размер кэша.
  • Предвыборка и предсказания ветвления.
  • Возможна большая эффективность в приложениях, включающих обработку больших массивов.

Пример 1

Matrices.cpp

 
#include <ctime>
    #include <iostream>
        #include "stdlib.h"
        #include "conio.h"
        #include "math.h"
        
        using namespace std;
        const int SIZE = 1000;
        
        void matrixMultiply(double ** matrA, double ** matrB, double ** matrC, int matrSize);
        double sinCosMultiply(double i, double j);
        
        int main()
        {
        time_t t1, t2;
        double trace(0);
        double ** matrixA = new double*[SIZE];
        double ** matrixB = new double*[SIZE];
        cout << "We will construct the square matrix " << SIZE << "x" << SIZE << endl;
        cout << "of pseudo-random values" << endl;
        cout << "and multiply it by itself. Then we will find the trace of the matrix." << endl;
        for(int i = 0; i < SIZE; i++)
        {
        matrixA[i] = new double[SIZE];
        matrixB[i] = new double[SIZE];
        }
        t1 = clock();
        for(int i=0; i<SIZE; i++)
        {
        for(int j=0; j<SIZE; j++)
            {
            matrixA[i][j]=sinCosMultiply(rand()%10/3, rand()%10/3);
            }}
            matrixMultiply(matrixA, matrixA, matrixB, SIZE);
            for(int i=0; i<SIZE; i++)
            {
            for(int j=0; j<SIZE; j++)
                {
                     if(i==j) trace += matrixB[i][j];
                     }
                     }
                     t2 = clock();
                     cout << "\nTrace is " << trace << endl;
                     cout << "\nInitial clock ticks value is " << t1 << endl;
                     cout << "Final clock ticks value is " << t2 << endl;
                     cout << "Difference in clock ticks is " << difftime(t2,t1) << endl;
                     cout << "Clock ticks per second value is " << CLOCKS_PER_SEC << endl;
                     cout << "\nActual time of calculations is " << ((t2-t1)/CLOCKS_PER_SEC) << " sec" << endl;
                     for(int i = 0; i < SIZE; i++)
                     {
                     delete [] matrixA[i];
                     delete [] matrixB[i];
                     }
                     delete [] matrixA;
                     delete [] matrixB;
                     return 0;
                     }
                     void matrixMultiply(double ** matrA, double ** matrB, double ** matrC, int matrSize)
                     {
                     for(int i=0; i<matrSize; i++)
                     {
                     for(int j=0; j<matrSize; j++)
                         {
                         matrC[i][j] = 0;
                         for(int k=0; k<matrSize; k++)
                         {
                         matrC[i][j] += matrA[i][k]*matrB[k][j];
                         }
                     }
               }
           }
                         
     double sinCosMultiply(double i, double j)
       {
       return sin(i)*cos(j);
        }    
        

Подготовим тест:

  • icl /FeMatricesOd /Od Matrices.cpp
  • icl /FeMatricesO1 /O1 Matrices.cpp
  • icl /FeMatricesO2 /O2 Matrices.cpp
  • icl /FeMatricesO3 /O3 Matrices.cpp

Intel Core 2 Duo T3700 2.00 ГГц, 2 Гб RAM

Среднее значение времени выполнения:

  • MatricesOd . . . 21.76 с.
  • MatricesO1 . . . 14.05 с.
  • MatricesO2 . . . 9.63 с.
  • MatricesO3 . . . 9.57 с.

Вопрос. Объясните результаты теста.

Лекция 1: 1234 || Лекция 2 >