2014-10-25 5 views
0

Я пишу программу MPI, и функция MPI_Bcast очень медленная на одной конкретной машине, которую я использую. Чтобы сузить проблему, у меня есть следующие две тестовые программы. Первый делает много операций MPI_Send/MPI_RECV от процесса 0 до других:MPI Broadcast Very Slow

#include <stdlib.h> 
#include <stdio.h> 
#include <mpi.h> 

#define N 1000000000 

int main(int argc, char** argv) { 
    int rank, size; 

    /* initialize MPI */ 
    MPI_Init(&argc, &argv); 

    /* get the rank (process id) and size (number of processes) */ 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 

    /* have process 0 do many sends */ 
    if (rank == 0) { 
    int i, j; 
    for (i = 0; i < N; i++) { 
     for (j = 1; j < size; j++) { 
     if (MPI_Send(&i, 1, MPI_INT, j, 0, MPI_COMM_WORLD) != MPI_SUCCESS) { 
      printf("Error!\n"); 
      exit(0); 
     } 
     } 
    } 
    } 

    /* have the rest receive that many values */ 
    else { 
    int i; 
    for (i = 0; i < N; i++) { 
     int value; 
     if (MPI_Recv(&value, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE) != MPI_SUCCESS) { 
     printf("Error!\n"); 
     exit(0); 
     } 
    } 
    } 

    /* quit MPI */ 
    MPI_Finalize(); 
    return 0; 
} 

Эта программа работает только в 2,7 секунды или около 4 процессов.

Это следующая программа делает то же самое, за исключением того, что использует MPI_Bcast послать значения от процесса 0 до других процессов:

#include <stdlib.h> 
#include <stdio.h> 
#include <mpi.h> 

#define N 1000000000 

int main(int argc, char** argv) { 
    int rank, size; 

    /* initialize MPI */ 
    MPI_Init(&argc, &argv); 

    /* get the rank (process id) and size (number of processes) */ 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 

    /* have process 0 do many sends */ 
    if (rank == 0) { 
    int i, j; 
    for (i = 0; i < N; i++) { 
     if (MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD) != MPI_SUCCESS) { 
     printf("FAIL\n"); 
     exit(0); 
     } 
    } 
    } 

    /* have the rest receive that many values */ 
    else { 
    int i; 
    for (i = 0; i < N; i++) { 
     if (MPI_Bcast(&i, 1, MPI_INT, 0, MPI_COMM_WORLD) != MPI_SUCCESS) { 
     printf("FAIL\n"); 
     exit(0); 
     } 
    } 
    } 

    /* quit MPI */ 
    MPI_Finalize(); 
    return 0; 
} 

Обе программы имеют одинаковое значение для N, и ни одна программа возвращает ошибка из вызовов связи. Вторая программа должна быть хотя бы немного быстрее. Но это не так, это намного медленнее примерно в 34 секунды - примерно в 12 раз медленнее!

Эта проблема проявляется только на одной машине, но не на других, даже если они работают с одной и той же операционной системой (Ubuntu) и не имеют совершенно другого оборудования. Кроме того, я использую OpenMPI для обоих.

Я действительно вытаскиваю волосы, у кого есть идея?

Спасибо за чтение!

ответ

2

Несколько наблюдений.

MPI_Bcast получает результат в буфер «& i». MPI_Recv получает результат в значение «&». Есть ли причина, по которой это решение было принято?

Модель Send/Recv, естественно, синхронизируется. Вызовы MPI_Send блокируются и сериализуются. Соответствующий MPI_Recv всегда должен быть готов при вызове MPI_Send.

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

Я скомпилировал и запускал программы с использованием IBM Platform MPI. Я снизил значение N на 100x10 миллионов, чтобы ускорить тестирование. Я изменил MPI_Bcast, чтобы получить результат в буфере «&», а не в буфер «& i». Я запускал каждый случай три раза и усреднял время. Время - это «реальное» значение, возвращаемое «временем» (это было необходимо, поскольку ранги выполнялись удаленно из команды mpirun).

С четырьмя рядами по общей памяти модель Send/Recv заняла 6,5 секунды, модель Bcast заняла 7,6 секунды.

С 32 рангами (8 узлов/4 узла, FDR InfiniBand) модель Send/Recv заняла 79 секунд, модель Bcast заняла 22 секунды.

С 128 рангом (16 узлов или 8 узлов, FDR Infiniband) модель Send/Recv заняла 134 секунды, модель Bcast заняла 44 секунды.

Учитывая эти тайминги ПОСЛЕ уменьшения значения N на 100x10000000, я собираюсь предположить, что время «2,7 секунды» было нерабочим. Дважды проверьте, что была выполнена какая-то фактическая работа.