Измерение задержки вещания в открытом формате MPI

Из прочтения документации MPI_Bcast является блокирующим вызовом (и, следовательно, boost :: mpi :: broadcast). Является ли измерение количества времени, которое требуется корневому узлу для широковещательной передачи, хорошей мерой времени, которое требуется для того, чтобы данные прошли от корневого узла ко всем другим узлам?

То есть

int64_t t1 = Utility::picosecondTime(); //exactly what it sounds like; utility that measures current time in picoseconds
boost::mpi::broadcast(communicator, variable, 0);
std::cout << "Broadcast took " << Utility::picosecondTime()-t1 << std::endl;

Или для прямого OpenMPI:

MPI_Comm comm;
int array[100];
...
int64_t t1 = Utility::picosecondTime();
MPI_Bcast( array, 100, MPI_INT, 0, comm);
std::cout << "Broadcast took " << Utility::picosecondTime()-t1 << std::endl;

2

Решение

MPI_BCAST обычно реализуется в виде дерева, где процессы в верхней части дерева могут выйти из алгоритма после завершения своей части вещания. Таким образом, если ранг 0 отправляет сообщения в ранги 1 и n / 2, он может уйти после того, как эти сообщения сделаны. Таким образом, ответ на ваш вопрос: нет, это не точное измерение.

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

2

Другие решения

Вы ошибаетесь блокирование а также глобально синхронный звонки. Единственная коллективная операция MPI, которая гарантированно является глобально синхронной, MPI_BARRIER — он не завершится, если все процессы не вызвали его. MPI позволяет другим коллективным вызовам возвращаться, как только процессу, который выполняет вызов, не нужно участвовать дальше.

MPI_BCAST в значительной степени пример последнего. Открытый MPI предоставляет несколько реализаций, среди которых: базовое линейное, двоичное дерево, биномиальное дерево и конвейер / цепочка. Каждая реализация может дополнительно сегментировать сообщение. Жестко закодированная эвристика используется во время выполнения для выбора одной конкретной реализации на основе размера сообщения и размера коммуникатора. С точки зрения корневого ранга одна и та же широковещательная операция может занять разное количество времени в зависимости от используемого алгоритма.

  • базовый линейный — этот использует кучу MPI_ISENDс последующим MPI_WAITALL и поэтому завершается только после того, как все посылки завершены, и информация достигла всех других рангов;
  • двоичное / биномиальное дерево — оно завершается после того, как сообщение было передано в ряды, являющиеся прямыми потомками корневого узла; ему все еще может потребоваться больше времени, чтобы добраться до всех узлов дерева;
  • конвейер — этот сегментирует сообщение и реализует конвейер, который передает сегменты от корневого ранга к следующему после него, который, в свою очередь, передает их следующему к следующему и т. д .; с большими сообщениями и в очень быстрых сетях (например, InfiniBand) завершение операции в корне означает, что глобальное завершение почти неизбежно;
  • цепочка — эта группа делит процессы на несколько групп, а затем реализует отдельный конвейер для каждой группы.

Вы можете применить определенный алгоритм, который будет использоваться Open MPI — просто взгляните на возможные значения coll_tuned_bcast_algorithm Параметр MCA и другие связанные параметры:

$ ompi_info --mca coll_tuned_use_dynamic_rules 1 --param coll tuned | grep bcast

Правильный способ измерить время для MPI_BCAST будет окружать его MPI_BARRIER звонки, но тогда вам также нужно будет правильно измерить издержки самого барьерного звонка и затем компенсировать его.

1