Я работаю над проблемой, которую можно распараллелить, используя одну операцию mpi_allgather или одну операцию mpi_scatter и одну операцию mpi_gather. Эти операции вызываются в цикле while, поэтому их можно вызывать много раз.
В реализации со схемой MPI_allgather я собираю распределенный вектор по всем процессам для решения дубликатов матриц. В другой реализации я собираю распределенный вектор на один процессор (корневой узел), решаю линейную систему на этом процессоре, а затем разбрасываю вектор решения на все процессы.
Мне любопытно узнать, значительно ли стоимость операции по сбору больше, чем операции рассеяния и сбора вместе взятых. Важна ли длина сообщения в его сложности? Это зависит от реализации MPI?
Редактировать:
MPI_Scatter
сопровождаемыйMPI_Gather
не обеспечивает такую же семантику связи, какMPI_Allgather
. Возможно, существует избыточность, когда вы выражаете операцию любым способом?MPI_Gather
а"MPI_Bcast
?Ответы:
Во-первых, точный ответ зависит от: (1) использования, то есть входных аргументов функций, (2) качества и подробностей реализации MPI и (3) используемого вами оборудования. Часто (2) и (3) связаны, например, когда поставщик оборудования оптимизирует MPI для своей сети.
В общем случае слияние коллективов MPI лучше для небольших сообщений, поскольку затраты на запуск могут быть нетривиальными, а синхронизация, вызванная блокировкой коллективов, должна быть сведена к минимуму, если есть различия во времени вычислений между вызовами. Для больших сообщений цель должна состоять в том, чтобы минимизировать объем отправляемых данных.
Например, в теории
MPI_Reduce_scatter_block
должно быть лучше, чемMPI_Reduce
следоватьMPI_Scatter
, хотя первое часто реализуется с точки зрения последнего, так что нет реального преимущества. Существует корреляция между качеством реализации и частотой использования в большинстве реализаций MPI, и поставщики, очевидно, оптимизируют те функции, для которых это требуется для машинного контракта.С другой стороны, если один находится на Blue Gene, делая при
MPI_Reduce_scatter_block
помощиMPI_Allreduce
, которая делает больше общения , чемMPI_Reduce
и вMPI_Scatter
сочетании, на самом деле совсем немного быстрее. Это то, что я недавно обнаружил, и является интересным нарушением принципа самосогласованности производительности в MPI (этот принцип более подробно описан в «Принципах самосогласованной производительности MPI» ).В конкретном случае разброса + сбора по сравнению со всем собранием, учтите, что в первом случае все данные должны идти в и из одного процесса, что делает его узким местом, в то время как во всем, данные могут поступать и выходить из всех рангов сразу потому что все ранги имеют некоторые данные для отправки во все другие ранги. Однако отправка данных со всех узлов одновременно не обязательно является хорошей идеей в некоторых сетях.
Наконец, лучший способ ответить на этот вопрос - сделать следующее в своем коде и ответить на вопрос экспериментально.
Еще лучший вариант состоит в том, чтобы ваш код измерял его экспериментально в течение первых двух итераций, а затем использовал тот, который быстрее для остальных итераций:
источник
Джефф абсолютно прав насчет единственного способа убедиться в том, что он измеряет - в конце концов, мы ученые, и это эмпирический вопрос - и дает отличный совет о том, как проводить такие измерения. Позвольте мне теперь предложить противоположное (или, может быть, дополнительное) мнение.
Необходимо сделать различие между написанием кода, который будет широко использоваться, и настройкой его для конкретной цели. В общем, мы делаем первое - строим наш код так, чтобы: а) мы могли использовать его на самых разных платформах, и б) код можно было поддерживать и расширять на долгие годы. Но иногда мы делаем другое - у нас есть годовой объем распределения на какой-то большой машине, и мы наращиваем некоторый необходимый набор больших симуляций, и нам нужен определенный базовый уровень производительности, чтобы получить то, что нам нужно сделать во время время предоставленного распределения.
Когда мы пишем код, сделать его широко применимым и обслуживаемым гораздо важнее, чем сэкономить несколько процентов времени выполнения на конкретной машине. В этом случае правильным решением будет почти всегда использовать процедуру, которая наилучшим образом описывает то, что вы хотите сделать - это, как правило, самый конкретный вызов, который вы можете сделать, который делает то, что вы хотите. Например, если прямой allgather или allgatherv делает то, что вы хотите, вы должны использовать это, а не выкатывать свои собственные из операций разброса / сбора. Причины таковы:
В этом довольно распространенном случае, если вы обнаружите, что некоторый коллектив MPI работает на вашем компьютере неоправданно медленно, лучше всего подать отчет об ошибке поставщику mpi; Вы не хотите усложнять свое собственное программное обеспечение, пытаясь обойти код приложения, что должно быть исправлено на уровне библиотеки MPI.
Однако . Если вы находитесь в режиме «настройки» - у вас есть рабочий код, вам нужно увеличить очень большие масштабы за короткий промежуток времени (например, годичное распределение), и вы профилировали свой код и обнаружил, что эта конкретная часть вашего кода является узким местом, тогда имеет смысл начать выполнять эти очень специфические настройки. Надеемся, что они не будут долгосрочными частями вашего кода - в идеале эти изменения останутся в какой-то конкретной ветке вашего репозитория - но вам, возможно, придется сделать это. В этом случае кодирование двух разных подходов, отличающихся директивами препроцессора, или подход «автонастройки» для конкретного шаблона связи - может иметь большой смысл.
Так что я не согласен с Джеффом, я просто хочу добавить некоторый контекст о том, когда вы должны быть достаточно обеспокоены такими относительными вопросами производительности, чтобы изменить свой код, чтобы справиться с ним.
источник