Это эталонный тест, который позволяет сравнивать производительность коллективной и двухточечной связи в общедоступной коммуникации,
#include <iostream>
#include <algorithm>
#include <mpi.h>
#define BUFFER_SIZE 16384
void point2point(int*, int*, int, int);
int main(int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int rank_id = 0, com_sz = 0;
double t0 = 0.0, tf = 0.0;
MPI_Comm_size(MPI_COMM_WORLD, &com_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &rank_id);
int* intSendPack = new int[BUFFER_SIZE]();
int* result = new int[BUFFER_SIZE*com_sz]();
std::fill(intSendPack, intSendPack + BUFFER_SIZE, rank_id);
std::fill(result + BUFFER_SIZE*rank_id, result + BUFFER_SIZE*(rank_id+1), rank_id);
// Send-Receive
t0 = MPI_Wtime();
point2point(intSendPack, result, rank_id, com_sz);
MPI_Barrier(MPI_COMM_WORLD);
tf = MPI_Wtime();
if (!rank_id)
std::cout << "Send-receive time: " << tf - t0 << std::endl;
// Collective
std::fill(result, result + BUFFER_SIZE*com_sz, 0);
std::fill(result + BUFFER_SIZE*rank_id, result + BUFFER_SIZE*(rank_id+1), rank_id);
t0 = MPI_Wtime();
MPI_Allgather(intSendPack, BUFFER_SIZE, MPI_INT, result, BUFFER_SIZE, MPI_INT, MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
tf = MPI_Wtime();
if (!rank_id)
std::cout << "Allgather time: " << tf - t0 << std::endl;
MPI_Finalize();
delete[] intSendPack;
delete[] result;
return 0;
}
// Send/receive communication
void point2point(int* send_buf, int* result, int rank_id, int com_sz)
{
MPI_Status status;
// Exchange and store the data
for (int i=0; i<com_sz; i++){
if (i != rank_id){
MPI_Sendrecv(send_buf, BUFFER_SIZE, MPI_INT, i, 0,
result + i*BUFFER_SIZE, BUFFER_SIZE, MPI_INT, i, 0, MPI_COMM_WORLD, &status);
}
}
}
Здесь каждый ранг добавляет свой собственный массив intSendPack
в массив result
во всех других рангах, который должен заканчиваться одинаково во всех рангах. result
является плоским, каждый ранг занимает BUFFER_SIZE
записей, начинающихся с rank_id*BUFFER_SIZE
. После связи точка-точка массив возвращается к своей первоначальной форме.
Время измеряется путем установки MPI_Barrier
, который даст вам максимальное время из всех рангов.
Я провел тест на 1 узле Nersc Cori KNL , используя slurm . Я запускал его несколько раз в каждом случае, просто чтобы убедиться, что значения согласованы, и я не смотрю на выбросы, но вы должны запустить его примерно 10 раз или около того, чтобы собрать более правильную статистику.
Вот некоторые мысли:
- Для небольшого числа процессов (5) и большого размера буфера (16384) коллективное взаимодействие происходит примерно в два раза быстрее, чем точка-точка, но оно становится примерно в 4-5 раз быстрее при переходе на большее количество рангов (64 ).
- В этом тесте нет большой разницы между производительностью с рекомендованными настройками slurm на этой конкретной машине и настройками по умолчанию, но в реальных, более крупных программах с большим количеством связи есть очень значительная (работа, которая выполняется менее минуты с рекомендуемой будет работать в течение 20-30 минут и более по умолчанию). Смысл в том, чтобы проверить ваши настройки, это может иметь значение.
- То, что вы видели при отправке / получении больших сообщений, фактически зашло в тупик. Я видел это также для размера сообщения, показанного в этом тесте. В случае, если вы пропустили это, на нем есть два достойных сообщения: объяснение буферизации и слово о блокировке .
Таким образом, настройте этот эталонный тест для более точного представления вашего кода и запуска его в вашей системе, но коллективное взаимодействие в ситуациях «все ко всем» или «один ко всем» должно быть быстрее из-за специальных оптимизаций, таких как превосходные алгоритмы используется для организации связи. Значительное ускорение в 2-5 раз, так как общение часто способствует увеличению общего времени.