Профилировка гибридных кластерных приложений MPI+OpenMP

d55c79a28e7d48718011d0f2796621fc.png

Библиотеки, реализующие стандарт MPI (Message Passing Interface) — наиболее популярный механизм организации вычислений на кластере. MPI позволяет передавать сообщения между узлами (серверами), но никто не мешает запускать несколько MPI процессов и на одном узле, реализуя потенциал нескольких ядер. Так часто и пишутся HPC приложения, так проще. И пока количество ядер на одном узле было мало, никаких проблем с «чистым MPI» подходом не было. Но сегодня количество ядер идёт на десятки, а то и на сотни для со-процессоров Intel Xeon-Phi. И в такой ситуации запуск десятков процессов на одной машине становится не совсем эффективным.

Дело в том, что MPI процессы общаются через сетевой интерфейс (хоть и реализованный через общую память на одной машине). Это влечет за собой избыточные копирования данных через множество буферов и увеличенный расход памяти.

Для параллельных вычислений внутри одной машины с общей памятью гораздо лучше подходят потоки и распределение задач между ними. Здесь наибольшей популярностью в мире HPC пользуется стандарт OpenMP.

Казалось бы — ладно, используем OpenMP внутри узла, и MPI для меж-узловых коммуникаций. Но не всё так просто. Использование двух фреймворков (MPI и OpenMP) вместо одного не только несёт дополнительную сложность программирования, но и не всегда даёт желаемый прирост производительности — по крайней мере, не сразу. Нужно ещё решить, как распределить вычисления между MPI и OpenMP, и, возможно, решить проблемы, специфичные для каждого уровня.

В этой статье я не буду описывать создание гибридных приложений — информацию найти не сложно. Мы рассмотрим, как можно анализировать гибридные приложения с помощью инструментов Intel Parallel Studio, выбирая оптимальную конфигурацию и устраняя узкие места на разных уровнях.
Для тестов будем использовать NASA Parallel Benchmark:

  • CPU: Intel Xeon processor E5–2697 v2 @ 2.70GHz, 2 сокета, 12 ядер в каждом.
  • OS: RHEL 7.0×64
  • Intel Parallel Studio XE 2016 Cluster Edition
  • Компилятор: Intel Compiler 16.0
  • MPI: Intel MPI library 5.1.1.109
  • Workload: NPB 3.3.1, «CG — Conjugate Gradient, irregular memory access and communication» module, class B


Бенчмарк уже реализован гибридным и позволяет конфигурировать количество MPI процессов и OpenMP потоков. Понятно, что для меж-узловых коммуникаций альтернативы MPI тут нет (в рамках нашего приложения). Интрига в том, что запускать на одном узле — MPI или OpenMP.
У нас в распоряжении 24 ядра. Начнём с традиционного подхода — только MPI. 24 MPI процесс, по 1 потоку на каждый. Для анализа программы воспользуемся новым инструментом, вышедшим в последней версии Intel Parallel Studio — MPI Performance Snapshot. Просто добавляем ключ »-mps» в строку запуска mpirun:

source /opt/intel/vtune_amplifier_xe/amplxe-vars.sh
source /opt/intel/itac/9.1.1.017/intel64/bin/mpsvars.sh --vtune
mpirun -mps –n 24 ./bt-mz.B.24
mps -g stats.txt app_stat.txt _mps


Первые две строки выставляют нужное окружение, третья запускает программу с профилировкой MPS. Последняя строка формирует отчёт в формате html. Без -g отчёт будет выведен на консоль — удобно для просмотра сразу на кластере, но в HTML красивее:

1a8fc7bd50a545eeab6d38275475ec1a.png
75f7c24c6a7248a5b9d555f2bf1dcc0b.png

MPS даёт верхнеуровневую оценку производительности. Накладные расходы на его запуск крайне малы, можно быстро сделать оценку приложения даже на больших масштабах (протестировано 32000 процессов).

Для начала смотрим доли MPI time и Computation time. У нас 32% времени уходит на MPI, почти всё из-за дисбаланса нагрузки — одни процессы ждут, пока другие считают. В блоках справа приводится оценка — время MPI помечено HIGH — слишком много тратиться на коммуникацию. Там же есть отсылка к другому инструменту — Intel Trace Analyzer and Collector (ITAC), для детального анализа MPI проблем. Про OpenMP никаких проблем не подсвечено, что неудивительно, ведь мы его фактически выключили.

MPS также считает аппаратные метрики эффективности: GFPLOS, CPI и метрику «Memory Bound» — общую оценку эффективности работы с памятью. А ещё потребление памяти (для одного MPI процесса) — максимальное и среднее.


MPS показал, что основная проблема в конфигурации »24×1» в MPI. Для выяснения причин собираем профиль ITAC:

source /opt/intel/itac/9.1.1.017/intel64/bin/itacvars.sh
mpirun -trace -n 24 ./bt-mz.B.24


Открываем трассу в ITAC GUI — я пользовался Windows версией. На графике Quantitative Timeline отчётливо видно, что доля MPI велика, и коммуникации распределены с некоторой цикличностью. Самый верхний график показывает периодические всплески MPI активности:

77a2d227044242ef9ab4fa93188c0608.png

Если выделить несколько таких всплесков на шкале Event Timeline, можно наблюдать, что коммуникации распределены неравномерно. Процессы с рангами 0–4 больше считают, а с рангами 15–23 больше ждут. Дисбаланс нагрузки налицо:

6c18fcdb5236462ab718df99c3b56bbf.png

На графике Message Profile можно оценить, какие именно процессы обмениваются сообщениями и где коммуникация наиболее долгая:

855ffb381ea24b4d8ed0e411ae85366a.png

Например, дольше других проходят сообщения между процессами с рангами 17 и 5, 16 и 0, 18 и 7, и т.д. Увеличив ещё сильнее Event Timeline, можно кликнуть по чёрной линии на 17-м ранге и посмотреть детали пересылки — от кого кому, размер сообщения, вызовы отправки и получения:

c7cd9ddcafde4433a653d6a1806bd547.png

Панель Performance Assistant описывает конкретные проблемы, найденные инструментом в выделенном регионе. Например, «поздняя отсылка»:

7c177eecc3d6450392b77830a3cad62c.png

Дисбаланс в MPI может быть вызван не только недостатками в коммуникационной схеме, но и проблемами в полезных вычислениях — когда одни процессы считают медленнее других. Если мы заинтересовались, на что это приложение тратит время внутри какого-то из процессов, и в чём могут быть проблемы, ITAC может сгенерировать командную строку для запуска Intel VTune Amplifier для этого ранга (например, на 2-го):

2bceb2fcd8e64857b735bf21f8e501ba.png
e33a60a6894b4b7c8a93e36c2becbb59.png

Но к VTune Amplifier вернёмся позже. Да и вообще, ITAC даёт массу возможностей для детального исследования MPI коммуникаций, но наша задача сейчас — выбрать оптимальный баланс между OpenMP и MPI. А для этого необязательно сразу исправлять MPI коммуникации на 24-х рангах — можно для начала попробовать другие варианты.


961f993af7eb4b359dd70ffbffb91b34.png
75c652b1c31846ffbb1dd85e1d28e846.png

Итак, эмпирическим путём получилось, что распределения 12×2 и 6×4 работают лучше других. Даже 2 OpenMP потока на каждый процесс существенно быстрее, чем 2 MPI процесса. Однако, с ростом числа потоков время работы снова начинает расти: 2×12 ещё хуже, чем «чистый MPI», а 1×24 даже приводить нет смысла. И виной всему дисбаланс работы, которая плохо распределяется по большому количеству OpenMP потоков. Вариант 2×12 имеет аж 30% дисбаланса.

Здесь мы вполне может остановиться, т.к. достигнутый компромисс 12×2 или 6×4 вполне приемлем. Но можно и копнуть глубже — поисследовать, в чём проблема с OpenMP масштабированием.


Для детального анализа проблем OpenMP отлично подойдёт Intel VTune Amplifier XE, о чём мы уже писалиподробно.

source /opt/intel/vtune_amplifier_xe/amplxe-vars.sh
mpirun -gtool "amplxe-cl -c advanced_hotspots -r my_result:1" -n 24 ./bt-mz.B.24


Для запуска анализаторов, таких как VTune Amplifier и Intel Advisor XE, стало очень удобно пользоваться синтаксисом опции gtool (только в Intel MPI). Она встраивается в строку запуска MPI приложения, позволяя запускать анализ лишь на выбранных процессах — в нашем примере только для ранга 1.

Посмотрим на профиль варианта »2 MPI процесса, 12 OpenMP потоков». В одном из наиболее затратных параллельных циклов 0.23 секунды из 1.5 уходит на дисбаланс. Дальше в таблице видно, что тип диспетчеризации статический, перераспределения работы не происходит. Кроме того, в цикле всего 41 итерация, а в соседних циклах 10–20 итераций. Т.е. при 12 потоках каждому достанется всего 3–4 итерации. Видимо, этого не достаточно для эффективного баланса нагрузки.

809edaa06f7243c988920e1debbd3fac.png

При 2–4 потоках каждому из них достаётся больше работы, и относительное время активного ожидания, вызванного дисбалансом, снижается. Что подтверждается профилем »6×4» — imbalance значительно ниже:

51ce57f97f174687896e25debd9cf977.png

Кроме того, в версии Intel VTune Amplifier 2016 появилось время MPI — колонка «MPI Communication Spinning» и жёлтая разметка на временной шкале. Можно запустить профиль VTune сразу для нескольких процессов на одном узле, и наблюдать MPI spinning вместе с OpenMP метриками в каждом из них:

56da6a025831479f9448adcd4ecd9339.png
f633cc85b50a47068ec38f70dec9dc75.png


Спускаясь ниже по уровням параллелизма, от масштаба кластера (MPI), до потоков одного узла (OpenMP) добираемся до параллелизма по данным внутри одного потока — векторизации, основанной на SIMD инструкциях. Здесь тоже может быть серьёзный потенциал для оптимизации, однако не зря мы добрались до него в последнюю очередь — сначала нужно решить проблемы на уровнях MPI и OpenMP, т.к. там потенциально можно больше выиграть. Про Advisor не так давно было два поста (первый и второй), поэтому здесь я ограничусь строкой запуска:

source /opt/intel/advisor_xe/advixe-vars.sh
mpirun -gtool "advixe-cl -collect survey --project-dir ./my_proj:1" -n 2 ./bt-mz.2


Дальше проводим анализ векторизации кода, как мы писали раньше. Advisor составляет важную часть экосистемы анализа кластерных MPI программ. Кроме глубокого исследования векторизации кода, Advisor помогает прототипировать многопоточное исполнение и проверяет шаблоны доступа к памяти.
Intel Parallel Studio предлагает четыре инструмента для анализа производительности гибридных HPC приложений:

  • MPI Performance Snapshot (уровень кластера) — быстрая оценка эффективности, минимальные накладные расходы, профилировка до 32000 MPI процессов, быстрая оценка дисбаланса MPI и OpenMP, общая оценка производительности (GFLOPS, CPI).
  • Intel Trace Analyzer and Collector (уровень кластера) — детальное исследование MPI, выявление шаблонов коммуникации, локализация конкретных узких мест.
  • Intel VTune Amplifier XE (уровень одного узла) — детальный профиль с исходным кодом и стэками, дисбалансы и другие проблемы OpenMP, анализ использования кэша и памяти и многое другое.
  • Intel Advisor XE (уровень одного узла) — анализ использования векторных инструкций и выявление причин их неэффективности, прототипирование многопоточного исполнения, анализ шаблонов доступа к памяти.


11fd72e7ce9944de97d22bb3632209ee.png

© Habrahabr.ru