Режимы отправки и приема MPI для большого количества процессоров

#c #performance #mpi #deadlock

#c #Производительность #mpi #тупиковая ситуация

Вопрос:

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

В любом случае, мой сценарий выглядит следующим образом. Код предназначен для высокопроизводительных кластеров с потенциально тысячами ядер, организованных в многомерную сетку. В моем алгоритме есть две последовательные операции, которые необходимо выполнить, назовем их A и B, где A предшествует B. Краткое описание выглядит следующим образом:

О: каждый процессор имеет несколько буферов. Он должен отправлять каждый из этих буферов определенному набору процессоров. Для каждого отправляемого буфера набор принимающих процессоров может отличаться. Отправка является последним шагом операции A.

B: каждый процессор получает набор буферов от набора процессоров. Затем операция B будет работать с этими буферами, как только она получит их все. Результат этой операции будет сохранен в фиксированном месте (ни в буферах отправки, ни в буферах приема)

Также задаются следующие свойства:

  • в A каждый процессор может вычислить, на какие процессоры отправлять, и он также может вычислить соответствующий тег в случае, если процессор получает несколько буферов от одного и того же отправляющего процессора (что очень вероятно).
  • в B каждый процессор также может вычислить, от каких процессоров он будет получать, и соответствующие теги, с которыми были отправлены сообщения.
  • Каждый процессор имеет свои собственные буферы отправки и буферы приема, и они не пересекаются (т. Е. Нет процессора, который также использует свой буфер отправки в качестве буфера приема, и наоборот).
  • A и B выполняются в цикле среди других операций перед A и после B. Мы можем гарантировать, что буфер отправки не будет использоваться снова до следующей итерации цикла, где он заполняется новыми данными в A, и буферы приема также не будут использоваться снова до следующей итерации, где они используются для получения новых данных в операции B.
  • Переход между A и B должен, по возможности, быть точкой синхронизации, т. Е. Мы хотим убедиться, что все процессоры входят в B одновременно

Для отправки и получения как A, так и B должны использовать (вложенные) циклы самостоятельно для отправки и получения разных буферов. Однако мы не можем делать никаких предположений о порядке этих операторов отправки и получения, т. Е. Для любых двух буферов buf0 , и buf1 мы не можем гарантировать, что если buf0 он получен каким-либо процессором ранее buf1 , он buf0 также был отправлен ранее buf1 . Обратите внимание, что на данный момент использование групповых операций, таких как MPI_Broadcast etc., пока не является вариантом из-за сложности определения набора процессоров приема / отправки.

Вопрос: Какие режимы отправки и получения я должен использовать? Я прочитал много разных материалов об этих разных режимах, но я не могу по-настоящему разобраться в них. Наиболее важным свойством является свобода от взаимоблокировки, а следующая важная вещь — производительность. Я склоняюсь к использованию MPI_Isend() в A без проверки статуса запроса и снова использую неблокирующее MPI_IRecv() в циклах B, а затем использую MPI_Waitall() , чтобы убедиться, что все буферы были получены (и, как следствие, также все буферы были отправлены и процессоры синхронизированы).

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

Ответ №1:

Из того, как вы описываете свою проблему, я думаю MPI_Isend , что это, вероятно, лучший (единственный?) Вариант для A, Потому что он гарантированно неблокирующий, тогда как MPI_Send может быть неблокирующим, но только если он способен внутренне буферизировать ваш буфер отправки.

Затем вы должны иметь возможность использовать an MPI_Barrier , чтобы все процессы вводили B одновременно. Но это может привести к снижению производительности. Если вы не настаиваете на том, чтобы все процессы вводили B одновременно, некоторые могут начать получать сообщения раньше. Кроме того, учитывая ваши непересекающиеся буферы отправки и приема, это должно быть безопасно.

Для B вы можете использовать MPI_Irecv или MPI_Recv . MPI_Irecv вероятно, будет быстрее, потому что стандарт MPI_Recv может ожидать более медленной отправки от другого процесса.

Независимо от того, блокируете вы на принимающей стороне или нет, вы должны вызвать MPI_Waitall перед завершением цикла, чтобы убедиться, что все операции отправки / recv завершены успешно.

Дополнительный момент: вы можете использовать MPI_ANY_SOURCE с MPI_Recv , чтобы получать сообщения блокирующим способом и немедленно обрабатывать их, независимо от того, в каком порядке они поступают. Однако, учитывая, что вы указали, что никакие операции с данными не выполняются до тех пор, пока не будут получены все данные, это может оказаться не столь полезным.

Наконец: как упоминалось в этих рекомендациях, вы получите максимальную производительность, если сможете реструктурировать свой код так, чтобы его можно было просто использовать MPI_SSend . В этом случае вы вообще избегаете какой-либо буферизации. Для достижения этого вам нужно, чтобы все процессы сначала вызывали an MPI_Irecv , а затем начинали отправку via MPI_Ssend . Возможно, провести рефакторинг таким образом не так сложно, как вы думаете, особенно если, как вы говорите, каждый процесс может самостоятельно определять, какие сообщения он будет получать от кого.

Комментарии:

1. Вы имели в виду MPI_Rsend() ?

2. Большое спасибо, все оказалось именно так, как вы сказали. Мы начали с использования неблокирующего, а теперь переработали весь код, чтобы использовать эту MPI_Issend() функцию в сочетании с MPI_Irecv() ранее опубликованным соответствием, и это работает как шарм.