Автовекторизатор

GPUs обрабатывают скалярные данные эффективно, но CPU потребности векторизованные данные для хранения его полностью занятым. Что означает, что, или Вы пишете различное ядро для каждого устройства, на котором Ваше приложение могло бы работать, каждый оптимизированный для того устройства, или производительность приложения пострадает.

Автовекторизатор обнаруживает операции в скалярной программе, которая может быть выполнена параллельно и преобразовывает их в векторные операции, которые могут быть обработаны эффективно сегодняшним CPUs. Если Вы знаете о выполнении кода через автовекторизатор можно записать единственную, простую скалярную программу, зная, что автовекторизатор векторизует тот код для Вас так, чтобы его производительность на CPU была максимизирована, в то время как тот же код работает на GPU, как записано.

Что делает автовекторизатор

Запись оптимального кода для CPU

Записать код, который может лучше всего быть оптимизирован автовекторизатором:

Сделать

  • Запишите единственное ядро, которое может работать на CPU и GPU. Используйте надлежащие типы данных (скаляр или плавание) по мере необходимости Вашим алгоритмом.

  • Переместитесь неконтролируемый доступ к памяти текут если возможный; например:

    if (condition)
       a[index] = 1
    else
       a[index] = 2

    должен быть кодирован как:

    if (condition)
      tmp = 1;
    else
      tmp = 2;
     
    a[index] = tmp;
  • При доступе к элементам матрицы, лучше доступ последовательные элементы матрицы в последовательных единицах работы. Посмотрите Таблицу 14-2 для реального примера того, как получить доступ к последовательным элементам матрицы в последовательных единицах работы наиболее эффективно.

Не делать

  • Запишите специфичную для устройства оптимизацию.

  • Запишите поток управления зависимого ID единицы работы, если это возможно. (Если бы это происходит во многих местах в коде, он, вероятно, препятствовал бы тому, чтобы успешно выполнилась автовекторизация.)

Включение и отключение автовекторизатора в XCode

Можно отключить или повторно включить автовекторизацию в настройках сборки XCode для приложений OpenCL. По умолчанию автовекторизатор включен при генерации ядер в XCode. Выбрать No выключить автовекторизатор. Эта установка вступает в силу только для CPU.

Установка

Ввести

Значение по умолчанию

Флаг командной строки

Автовекторизатор

Булевская переменная

ДА

Включить: -cl-auto-vectorize-enable

Отключить: -cl-autovectorize-disable

Пример: автовекторизация скалярных плаваний

OpenCL рассматривает устройства как наличие, много вычисляют ядра и в них много элементов обработки. Когда скалярный код работает на CPU, он работает на каждом ядре, но не использует в своих интересах весь векторный модуль.

Например, на SSE4 CPU, скаляр кодирует выполнения в одном маршруте векторного модуля, когда это могло работать в четырех маршрутах. Монитор сообщил бы, что CPU абсолютно занят, потому что все ядра работают, но CPU фактически только использует четверть его векторной ширины.

Рисунок 13-1  Перед автовекторизацией: простое плавание отправило к CPU и GPU

Перечисление 13-1 является примером ядра, принимающего простые плавания:

Перечисление 13-1  , Передающее единственные плавания в ядро

kernel void add_arrays(global float* a, global float* b, global float* c)
{
  size_t i = get_global_id(0);
  c[i] = a[i] + b[i];
}

При передаче простых плаваний в ядро ядро делает скалярное дополнение; работа на одном элементе данных за один раз. Как проиллюстрировано на рисунке 13-1 при передаче скалярного плавания GPU GPU становится полностью занятым обработкой данных. При передаче этого того же плавания CPU только одна четверть векторной ширины элемента обработки в каждом ядре используется.

Вы могли вместо этого передать float4* параметры к ядру, делающему дополнение векторным дополнением. Вычисление теперь специализировано для CPU. Это извлекло бы как можно больше работы от CPU, но оставило бы GPU неактивным.

Без автовекторизатора необходимо было бы записать многократные специфичные для устройства, нескалярные ядра, один для CPU и один для GPU.