Опубликован: 19.10.2012 | Доступ: свободный | Студентов: 299 / 65 | Длительность: 05:51:00
Лекция 4:

Элементные функции. Функции прикладного программного интерфейса

Аннотация: Лекция посвящена элементным функциям в Intel® CilkTM Plus, а также функциям прикладного программного интерфейса. Обсуждаются вопросы повышения производительности.

Презентацию к лекции Вы можете скачать здесь.

Эффективная векторизация – как её добиться?

Векторизация в рамках C/C++. Недостаток – не всегда удобная реализация.

Использование расширения процессорных инструкций SSE (Streaming SIMD Extension). Недостаток – фиксированная длина вектора.

Использование элементных операций/функций Intel® CilkTM Plus.

Элементные функции

Элементные функции формируют результат вычисления скалярной функции для каждого элемента массива (вызов скалярной функции с векторным аргументом формирует массив значений, конформный аргументу):

__declspec(vector) <сигнатура функции>

Отображение заменяет цикл последовательной программы.

Примеры:

a[:] = sin(b[:]);
a[:] = pow(b[:], c); // b[:]**c
a[:] = pow(c, b[:]); // c**b[:]
f(b[:])

При компиляции кода с вызовом элементных функций компилятор генерирует обращения к векторизованным функциям.

Компилятор может генерировать многопоточный код.

Если функция определена как elemental, компилятор генерирует векторизованный код для этой функции.

Исключены побочные эффекты.

Функции отображаются параллельно!

Ограничения

  1. Допускается использование только следующих типов:
    • signed/unsigned 8/16/32/64 битовые целые;
    • 32 или 64 битовые с плавающей точкой;
    • 64 или 128 битовые комплексные;
    • указатель или ссылка C++.
  2. Не допускается использование ключевых слов for, while, do, goto.
  3. Не допускается использование операторов выбора.
  4. Не допускается использование ассемблерных вставок.
  5. В функциях не допускается многопоточность, реализованная с помощью , OpenMP, cilk_spawn/cilk_for.
  6. Не допускаются виртуальные функции и указатели на функции.
  7. В функциях не допускается использование выражений с индексной нотацией.

и другие.

Пример

float saxpy(float a, float *x, float *y);
void foo(float *x, float *y, float a, int len) {
   for(int i = 0; i < len; i++)
        saxpy(a, x[i], y[i]);
}


void saxpy(float a, float *x, float *y) {
   *y += a * (*x); 
}
__declspec(vector(scalar(a),linear(x),linear(y)))
void saxpy(float a, float *x, float *y);
void foo(float *restrict x, float *restrict y, float a, int len) {
      saxpy(a, x[0:len], y[0:len]);
}

Компилятор сгенерирует вот такой код:

void saxpy_4(float a, float x[4],  float y[4]) 
{
    y[:] += a * x[:];
}
for(i = 0; i < len-3; i += 4) {   
    saxpy_4(a, &x[i], &y[i]);
}
for(; i < len; i++) {   
    saxpy(a, &x[i], &y[i]);
}

Примеры применения (по предметным областям):

  • обработка изображений (гамма-коррекция и т.д.);
  • преобразование между цветовыми пространствами;
  • моделирование методом Монте-Карло.

Дополнительные примеры использования отображения функций

Параллелизм потоков

cilk_for( int i=0; i<n; ++i )
    a[i] = f(b[i]);

Векторный параллелизм

a[0:n] = f(b[i:n]);

#pragma simd
for( int i=0; i<n; ++i )
    a[i] = f(b[i]);

Пример использования отображения функций в Intel® Threading Building Blocks

parallel_for( 0, n, [&]( int i ) {
    a[i] = f(b[i]);
});

parallel_for( 
    blocked_range<int>(0,n), 
    [&](blocked_range<int> r ) {
        for( int i=r.begin(); i!=r.end(); ++i ) 
            a[i] = f(b[i]);
    });