2014-01-08 1 views
7

Я хочу использовать MPI_Iprobe, чтобы проверить, не отправлено ли сообщение с заданным тегом.Почему MPI_Iprobe возвращает false, когда сообщение определенно отправлено?

Однако поведение MPI_Iprobe не совсем так, как я ожидал. В приведенном ниже примере я отправляю сообщения из нескольких задач на одну задачу (ранг 0). Затем в ранге 0 я жду несколько секунд, чтобы дать много времени для завершения MPI_Isends. Затем, когда я запускаю MPI_Iprobe, он возвращается с флагом false. Если я повторяю после (блокирующего) MPI_Probe, он возвращает true.

#include "mpi.h" 
#include <stdio.h> 
#include <unistd.h> 

int main(int argc, char *argv[]) 
{ 
    int rank; 
    int numprocs; 
    int tag; 
    int receive_tag; 
    int flag=0; 
    int number; 
    int recv_number=0; 

    MPI_Request request; 
    MPI_Status status; 

    MPI_Init(&argc,&argv); 
    MPI_Comm_rank(MPI_COMM_WORLD,&rank); 
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs); 

    // rank 0 receives messages, all others send messages 
    if (rank > 0) { 
    number = rank; 
    tag = rank; 
    MPI_Isend(&number, 1, MPI_INT, 0, tag, MPI_COMM_WORLD,&request); // send to rank 0 
    printf("Sending tag : %d \n",tag); 
    } 
    else if (rank == 0) { 

    sleep(5); // [seconds] allow plenty of time for all sends from other tasks to complete 

    receive_tag = 3; // just try and receive a single message from task 1 

    MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status); 
    printf("After MPI_Iprobe, flag = %d \n",flag); 

    MPI_Probe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&status); 
    printf("After MPI_Probe, found message with tag : %d \n",receive_tag); 

    MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status); 
    printf("After second MPI_Iprobe, flag = %d \n",flag); 

    // receive all the messages 
    for (int i=1;i<numprocs;i++){  
    MPI_Recv(&recv_number, 1, MPI_INT, MPI_ANY_SOURCE, i, MPI_COMM_WORLD,&status); 
    printf("Received : %d \n",recv_number); 
    } 

} 
MPI_Finalize(); 
} 

дает этот вывод:

Sending tag : 4 
Sending tag : 3 
Sending tag : 2 
Sending tag : 5 
Sending tag : 1 
After MPI_Iprobe, flag = 0 
After MPI_Probe, found message with tag : 3 
After second MPI_Iprobe, flag = 1 
Received : 1 
Received : 2 
Received : 3 
Received : 4 
Received : 5 

Почему обратный mpi_iprobe 'ложный' в первый раз?

Любая помощь была бы высоко оценена!


EDIT: после ответа Христо Илиев теперь у меня есть следующий код:

#include "mpi.h" 
#include <stdio.h> 
#include <unistd.h> 

int main(int argc, char *argv[]) 
{ 
    int rank; 
    int numprocs; 
    int tag; 
    int receive_tag; 
    int flag=0; 
    int number; 
    int recv_number=0; 

    MPI_Request request; 
    MPI_Status status; 

    MPI_Init(&argc,&argv); 
    MPI_Comm_rank(MPI_COMM_WORLD,&rank); 
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs); 

    // rank 0 receives messages, all others send messages 
    if (rank > 0) { 
    number = rank; 
    tag = rank; 

    MPI_Isend(&number, 1, MPI_INT, 0, tag, MPI_COMM_WORLD,&request); // send to rank 0 
    printf("Sending tag : %d \n",tag); 

    // do stuff 

    MPI_Wait(&request,&status); 
    printf("Sent tag : %d \n",tag); 

    } 
    else if (rank == 0) { 

    sleep(5); // [seconds] allow plenty of time for all sends from other tasks to complete 

    receive_tag = 3; // just try and receive a single message from task 1 

    MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status); 
    printf("After MPI_Iprobe, flag = %d \n",flag); 

    MPI_Probe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&status); 
    printf("After MPI_Probe, found message with tag : %d \n",receive_tag); 

    MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status); 
    printf("After second MPI_Iprobe, flag = %d \n",flag); 

    // receive all the other messages 
    for (int i=1;i<numprocs;i++){ 
     MPI_Recv(&recv_number, 1, MPI_INT, MPI_ANY_SOURCE, i, MPI_COMM_WORLD,&status); 
    } 

} 
MPI_Finalize(); 
} 

который дает следующий результат:

Sending tag : 5 
Sending tag : 2 
Sending tag : 1 
Sending tag : 4 
Sending tag : 3 
Sent tag : 2 
Sent tag : 1 
Sent tag : 5 
Sent tag : 4 
Sent tag : 3 
After MPI_Iprobe, flag = 0 
After MPI_Probe, found message with tag : 3 
After second MPI_Iprobe, flag = 1 

ответ

10

Вы используете MPI_Isend для того, чтобы отправить сообщений. MPI_Isend- - асинхронный (фоновый) способ передачи данных. Фактическая передача данных может не произойти, если только один из звонков или MPI_Test* был выполнен по запросу. Некоторые реализации MPI имеют (или могут быть настроены так) потоки фоновой прогрессии, которые будут продвигать операцию отправки, даже если в запросе не было ожиданий/тестов, но не следует полагаться на такое поведение.

Просто замените MPI_Isend с MPI_Send или добавить MPI_Wait(&request); после прежнего (виду, что хотя MPI_Isend + MPI_Wait сразу после эквивалентно MPI_Send).

MPI_Iprobe предназначен для использования в людных ждет, т.е .:

while (condition) 
{ 
    MPI_Iprobe(...,&flag,...); 
    if (flag) 
    { 
     MPI_Recv(...); 
     ... 
    } 
    // Do something, e.g. background tasks 
} 

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

Реализация MPI из MPI_PROBE и MPI_IPROBE потребности, чтобы гарантировать прогресс: если вызов MPI_PROBE был выдан процессом, и посыл, который соответствует зонду был инициирован каким-либо процесс, то вызов MPI_PROBE вернется, если сообщение не получено другой параллельной операцией приема (выполняемой другим потоком в процессе зондирования).Аналогичным образом, если процесс занят с MPI_IPROBE и получено соответствующее сообщение, то вызов MPI_IPROBE в конечном итоге возвращает flag = true, если сообщение не получено другой операцией одновременного приема.

Обратите внимание на использование в конечном итоге. Как прогрессирование делается очень специфично для реализации. Сравните следующий вывод из 5 последовательных вызовов на MPI_Iprobe (исходный код + жесткий цикл):

Open MPI 1.6.5 без прогрессии резьбы:

# Run 1 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 

# Run 2 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 

# Run 3 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 

Нет согласованности между несколькими казнями одного и того же Программа MPI наблюдается, и в 3-м пробеге флаг по-прежнему false после 5 вызываний MPI_Iprobe.

Intel MPI 4.1.2:

# Run 1 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 

# Run 2 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 

# Run 3 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 0 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 
After MPI_Iprobe, flag = 1 

Очевидно Intel MPI прогрессирует вещи иначе, чем Open MPI.

Разница между двумя реализациями может быть объяснена тем фактом, что MPI_Iprobe должен быть крошечным зондом, и поэтому он должен занимать как можно меньше времени. Прогрессия с другой стороны требует времени, а в однопоточных реализациях MPI единственный момент времени, когда возможна прогрессия, - это вызов MPI_Iprobe (в этом конкретном случае). Поэтому разработчик MPI должен решить, сколько на самом деле продвигается по каждому вызову до MPI_Iprobe и балансирует баланс между объемом работы, выполняемой вызовом, и временем, которое требуется.

С MPI_Probe Все по-другому. Это блокирующий вызов, и поэтому он может постоянно прогрессировать, пока не появится соответствующее сообщение (и, более конкретно, его огибающая).

+0

Спасибо, я только что попробовал заменить MPI_Isend на MPI_Send, как вы сказали, но по какой-то причине первый MPI_Iprobe все еще возвращает false. (То же самое происходит, если я использую MPI_Isend с MPI_Wait) ... –

+0

Для информации, я добавил свой новый код и вывод в приведенном выше редактировании (в вопросе). –

+1

'MPI_Iprobe' предназначен для использования в циклах с ожиданным циклом ожидания. Может потребоваться несколько вызовов 'MPI_Iprobe' до того, как операция будет выполнена правильно. «MPI_Probe» блокируется, и поэтому он не возвращается до того, как операция была выполнена до того момента, когда конверт сообщения был получен и согласован. –

Смежные вопросы