Параллельное программирование с использованием архитектуры Haswell

Я хочу узнать о параллельном программировании с использованием микроархитектуры процессора Intel Haswell. Об использовании SIMD: SSE4.2, AVX2 в asm/C/С++/(любые другие языки)?. Можете ли вы порекомендовать книги, учебные пособия, интернет-ресурсы, курсы?

Спасибо!

Ответ 1

Мне кажется, что вам нужно узнать о параллельном программировании в целом на процессоре. Я начал изучать это примерно 10 месяцев назад, прежде чем использовать SSE, OpenMP или встроенные средства, поэтому позвольте мне кратко изложить некоторые важные концепции, которые я узнал, и некоторые полезные ресурсы.

Существует несколько технологий параллельных вычислений: MIMD, SIMD, уровень команд parallelism, многоуровневые cahces и FMA. С Haswell есть также вычисления на IGP.

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

MIMD

В MIMD я имею в виду вычисления с использованием нескольких физических ядер. Я рекомендую OpenMP для этого. Пройдите этот урок http://bisqwit.iki.fi/story/howto/openmp/#Abstract а затем используйте это как ссылку https://computing.llnl.gov/tutorials/openMP/. Две наиболее распространенные проблемы с использованием MIMD: условия гонки и ложное разделение. Следите за OpenMP на SO reguarly.

SIMD

Многие компиляторы могут выполнять автоинтеграцию, поэтому я бы посмотрел на это. Автоинтеграция MSVC довольно примитивна, но GCC действительно хороша.

Изучите внутреннюю среду. Лучший ресурс, чтобы знать, что такое внутреннее, - http://software.intel.com/sites/landingpage/IntrinsicsGuide/

Еще один отличный ресурс - Agner Fog vectorclass. На 95% вопросов на SO на SSE/AVX можно ответить, посмотрев исходный код векторного класса. Кроме того, вы можете использовать векторный класс для большинства SIMD и все равно получить полную скорость и пропустить встроенные функции.

Многие люди используют SIMD неэффективно. Читайте о массиве структур (AOS) и структуре массивов (SOA) и массиве структуры массивов (AOSOA). Также посмотрите на интеллектуальную разработку Intel Вычисление матричного продукта намного медленнее с SSE, чем с прямым алгоритмом

См. Ingo Wald PhD thesis для интересного способа реализации SIMD в трассировке лучей. Я использовал ту же идею для набора Мандельброта для вычисления 4 (8) пикселей одновременно с помощью SSE (AVX).

Также прочитайте эту статью "Расширение C-подобного языка для портативного программирования SIMD" от Wald http://www.cdl.uni-saarland.de/papers/leissa_vecimp_tr.pdf, чтобы лучше понять, как для использования SIMD.

FMA

FMA3 является новым с Хасуэлла. Это так ново, что на SO нет много дискуссий. Но этот ответ (на мой вопрос) хорош Как использовать инструкции Fused Multiply-Add (FMA) с SSE/AVX. FMA3 удваивает пиковые FLOPS, поэтому потенциальное умножение матрицы в два раза быстрее на Хасуэлла по сравнению с мостом Айви.

В соответствии с этим ответом наиболее важным аспектом FMA является не тот факт, что одна команда вместо двух выполняет умножение и добавляет к ней "(практически) бесконечную точность промежуточного результата". Например, для реализации двойного двойного умножения без FMA требуется 6 умножений и несколько добавлений, тогда как с FMA это всего две операции.

Уровень команды parallelism

Haswell имеет 8 портов, которые он может отправлять μ-ops (хотя не каждый порт может принимать один и тот же mirco-op, см. это AnandTech review). Это означает, что Хасуэлл может сделать, например две 256-битные нагрузки, одно 256-битное хранилище, две 256-битные операции FMA, одно скалярное добавление и скачок состояния в одно и то же время (шесть μ-ops за такт).

По большей части вам не нужно беспокоиться об этом, так как это делает процессор. Однако бывают случаи, когда ваш код может ограничить потенциальный уровень команды parallelism. Наиболее распространенной является зависимость от цикла. Следующий код имеет зависимую от цикла зависимость

for(int i=0; i<n; i++) {
    sum += x(i)*y(i);
}

Способ исправить это - развернуть цикл и сделать частичные суммы

for(int i=0; i<n; i+=2) {
    sum1 += x(i)*y(i);
    sum2 += x(i+1)*y(i+1);
}
sum = sum1 + sum2;

Многоуровневые кэши:

Haswell имеет до четырех уровней кешей. Написание вашего кода для оптимального использования кеша является, по моему мнению, самой сложной задачей. Это тема, с которой я по-прежнему больше всего борется и чувствую себя самой неосведомленной, но во многих случаях улучшение использования кеша дает лучшую производительность, чем любая другая технология. У меня нет много рекомендаций для этого.

Вам нужно узнать о наборах и строках кэша (и критическом шаге) и о системах NUMA о страницах. Чтобы узнать немного о наборах и критический шаг, см. Agner Fog http://www.agner.org/optimize/optimizing_cpp.pdf, и это Почему перенос матрицы 512x512 намного медленнее, чем перенос матрицы из 513x513?

Еще одна очень полезная тема для кэша - блокирование или чередование циклов. См. Мой ответ (тот, который имеет самые высокие голоса) в Каков самый быстрый способ транспонирования матрицы в С++? для примера.

Вычисление на IGP (с Iris Pro).

Все потребительские процессоры Haswell (Haswell-E еще не вышли) имеют IGP. IGP использует по меньшей мере 30% кремния более чем на 50%. Это достаточно для по меньшей мере еще двух ядер x86. Это недостаток вычислительного потенциала для большинства программистов. Единственный способ программирования IGP - это OpenCL. У Intel нет драйверов OpenCL Iris Pro для Linux, поэтому вы можете работать только с Windows (я не уверен, насколько хороша эта реализация Apple). Программирование аппаратного обеспечения Intel IGP (например, Iris Pro 5200) без OpenCL.

Одно из преимуществ Iris Pro по сравнению с Nvidia и AMD заключается в том, что двойной плавающей точкой является на одну четверть скорости одиночной с плавающей запятой с Iris Pro ( однако fp64 включен только в Direct Compute, а не в OpenCL). NVIDIA и AMD (недавно) калечат двойную плавающую точку настолько, что делают вычисления с плавающей запятой GPGPU не очень эффективными на своих потребительских картах.