SSE

Опять о современных CPU

Продолжаю набирать материал к вот этой презентации

Вот такой вот код (это автобаланс белого из dcraw в моем вольном изложении, слегка сокращенный, только для 4-компонентных а не байеровских изображений):

float sum[8],dsum[8]={0,0,0,0,0,0,0,0};
for
...

Об эффективном использовании современных CPU

Практика вот к этой презентации:

Берем 36Mpix файлик с D800, распаковываем егонный RAW в 16-битный однокомпонентный битмеп, дальше начинаем процессить.

Процессим без "интерполяции", т.е. 4 пикселя исходного байера образуют один выходной пиксель (режим half_size у LibRaw/dcraw). Получаем такие вот времена:

  1. LibRaw::dcraw_process() плюс формирование RGBA-битмепа: 420ms.
  2. Перепишем этот самый dcraw_process() на SSE3, процессить будем в плавучке (с эмуляцией особенностей dcraw), выдаем такой же 8-битный RGBA: 110ms (и более-менее понятно где еще выиграть миллисекунд 20).
  3. Добавим в
  4. ...

Презентация с Highload

По просьбам трудящихся масс, моя презентация с Хайлоада:

Никаких откровений нет, задача была - показать что multicore/simd - это очень просто и стоит того. Читатели моего уютненького легко узнают примеры 1.5-2-летней давности.

Анимированность Slideshare порезала, но вроде накрывающих друг друга картинок у меня нет.

Про AVX и ISPC

Разработчики Intel SPMD Program Compiler, который в этом блоге уже несколько раз поминался, выпустили версию 1.0.9 в которой

=== v1.0.9 === (26 September 2011)

The binary release of v1.0.9 is the first that supports AVX code generation. Two targets are provided: "avx", which runs with a programCount of 8, and "avx-x2" which runs 16 program instances simultaneously.

Честь им за это и хвала, мои попытки (не слишком настойчивые) самостоятельно собрать ISPC с LLVM3 так...

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

Тема матричного цветопреобразования не отпускает нас.

Наш читатель maratyszcza намекает нам, что haddps - тоже хорошая инструкция.

Его вариант вы найдете по вышеуказанной ссылке, а я потестировал вариант попроще, без unroll, без префетча, без одновременной обработки половинок данных. Исключительно для совместимости с прошлыми тестами:

ALIGN1(32) float _m_zero[8] ALIGN2(32)
...

О векторном умножении - финал

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

Ассемблерные упражнения на тему векторных расширений.

SSE2-код

Сразу оговорка про Core2: быстродействие всех рассмотренных ниже сниппетов на этом процессоре практически одинаково, судя по всему все уперлось в память. А вот разница на Core i7-AVX довольно существенна.

Код, аналогичный тому, что делает хороший компилятор из векторного кода.

...

Опять про movntps

Читал комментарии к прошлому посту про movntps, много думал. Вспоминал, что на i7-920 выигрыш от movntps был и значительный.

Пришлось потратить час-полтора на очередной набор микробенчмарок. Картинка получилась куда сложнее, чем я сначала подумал.

Код

Может быть три легко локализуемых случая:

  • fill - данные как-то производятся из ничего и льются в память;
  • copy - из одного места читаем, в другое пишем;
  • stream - читаем данные, обрабатываем, пишем на старое место.

Соответственно, код для...

О векторных расширениях gcc/clang (2)

В комментариях к одному из предыдущих постов про оптимизацию матричного преобразования цвета нам предлагают немножко подумать над алгоритмом.

К сожалению, предложенное там решение (офигенно быстрое!) считает неправильно, но направление движение указано верно и мы приходим к такому варианту:

  1. транспонируем матрицу, на которую умножаем, дополним нулями правую колонку, чтобы вышло 4x4
  2. Каждое из (четырех) входных значений - размножим на вектор.
  3. Нужный нам результат - это SIMD-сумма SIMD-произведений вышеупомянутых векторов на строки вышеупомянутой транспонированной матрицы.
Короче, проще...

О компиляторах и процессорах

В комментариях к моему посту о целых числах и плавающей точке мне посоветовали обратить внимание на векторные типы данных и сравнить их по производительности со скалярными типами (ну и ручным SSE-ассемблером тоже).

Я обратил и сравнил, но в процессе получилась масса побочных результатов (разные архитектуры, разные компиляторы), которые жалко выкинуть, а хочется опубликовать.

Код

Я развлекался с кодом пересчета цветов по матричному профилю, только с матричной его частью, без пересчета гаммы. Оригинал был взят...

О legacy и форматах данных

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

А я вот тут читаю ассемблер, порожденный компилятором из C-шного кода обработки изображения. Много думаю.

Имею сказать, что распространенный в настоящее время формат "16-битное целое на компонент" - это максимально неудачный способ с точки зрения эффективности обработки:

  • от малейшего чиха переполняется или превращается в тыкву обнуляется, нужно постоянно следить за диапазоном;
  • векторные (SSE,AVX) операции
  • ...

Об автоматической векторизации

Провел на поминавшемся вчера ISPC еще один тест, на применимость ровно в том месте, куда он лучше всего приспособлен.

Есть такое ужасное место в обработке изображений (уже поминавшееся в этом блоге): преобразование из линейной гаммы в sRGB-гамму или в Lab. Там в формуле сначала линейный участок, а потом степенной. Вот как это выглядит, если делать в лоб для плавающей точки:

void linear2srgb(float *in,
...

Об Intel ISPC

Интел выкатил в опенсорс такую вот игрушку: Intel SPMD Program Compiler.

Это очередная попытка придумать параллельный язык C: пишете некую функцию, к примеру, обрабатывающую элемент данных, варез сам строит SIMD-представление (SSE, AVX), которое обрабатывает 4(8) элементов за раз. Ну как-то так:

void vector_sum(uniform float in[], uniform int count, reference uniform float out[])
...

OpenMP: Intel vs Visual Studio

Непонятки с производительностью OpenMP в случае VisualStudio (см. еще обсуждение в каментах) заставило разобраться.

Выяснилось, что две переменные, которые read-only и вообще объявлены как const - считаются разделяемыми. Как следствие - локи при обращении и прочие удовольствия.

После устранения этого недоразумения (#pragma omp ... private(...)) и замены _mm_store_ps() на _mm_stream_ps(), чтобы в обеих компиляторах выходной массив писался через movntps, все встало на свои места: С-шный код с powf() остается сильно быстрее у Интела т.к. он...

О степенной функции, OpenMP и прочих граблях

Есть вот такое вот известное выражение, переложеное из википедии:

#define To_sRGB(q) (((q)<=0.0031308f)? 12.92f*(q) : (1+0.055f)*powf(q,1/2.4f)-0.055f)
В том смысле, что у sRGB внизу - линейный участок, а дальше степенная функция.

Если его напрямую запрограммировать (вот прямо с powf()), то в зависимости от компилятора получается от 7 Mpix/sec (Visual C++ 2010, один поток) до 100Mpix/sec (Intel Parallel Studio XE, включен OpenMP). Пиксель - это 3 компонента по 4 байта (float), то бишь гигабайт с...

Полна чудес могучая природа

А в SSE4.1 оказывается есть минимум-максимум для 16-битных целых. 8 штук зараз.

Хреначит 11 гигабайт в секунду, сдается мне что параллелить по ядрам дальше смысла нет, упрешься в память.

И dot-product есть, правда только для float/double.

Чешутся руки забить на владельцев AMD и всего младше Penryn, держите меня...

Subscribe to SSE