2015-06-05 3 views
1

Я пишу программу, в которой процесс 0 отправляет части изображения другим процессам, которые преобразуют (длинную операцию) эту часть и отправляют обратно в ранг 0. У меня есть проблема с одна вещь. Чтобы воспроизвести мою проблему, я написал простой пример. Изображение размером 512x512px разделяется на 4 части (вертикальные полосы) процессом 0. Следующие другие процессы сохраняют эту часть на диске. Проблема в том, что каждый процесс сохраняет одну и ту же часть. Я обнаружил, что изображение разделено на части правильно, но проблема, вероятно, связана с отправкой данных. Что случилось в моем коде?MPI - отправка частей изображения в разные процессы

Пробег:

mpirun -np 5 ./example 

Главная:

int main(int argc, char **argv) { 

    int size, rank; 
    MPI_Request send_request, rec_request; 
    MPI_Status status; 
    ostringstream s; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    if (rank == 0) { 

     Mat mat = imread("/home/user/original.jpg", CV_LOAD_IMAGE_COLOR); 
     if (!mat.data) exit(-1); 

     int idx = 1; 
     for (int c = 0; c < 512; c += 128) { 
      Mat slice = mat(Rect(c, 0, 128, 512)).clone(); 
      MPI_Isend(slice.data, 128 * 512 * 3, MPI_BYTE, idx, 0, MPI_COMM_WORLD, &send_request); 
      idx++; 
     } 
    } 
    if (rank != 0) { 
     Mat test = Mat(512, 128, CV_8UC3); 
     MPI_Irecv(test.data, 128 * 512 * 3, MPI_BYTE, 0, 0, MPI_COMM_WORLD, &rec_request); 
     MPI_Wait(&rec_request, &status); 

     s << "/home/user/p" << rank << ".jpg"; 
     imwrite(s.str(), test); 
    } 

    MPI_Finalize(); 
    return 0; 
} 

ответ

2

Если вы настаиваете на использовании неблокируемые операций, то надлежащим образом оформить кратна них в то же время:

MPI_Request *send_reqs = new MPI_Request[4]; 

int idx = 1; 
for (int c = 0; c < 512; c += 128) { 
    Mat slice = mat(Rect(c, 0, 128, 512)).clone(); 
    MPI_Isend(slice.data, 128 * 512 * 3, MPI_BYTE, idx, 0, MPI_COMM_WORLD, &send_reqs[idx-1]); 
    idx++; 
} 

MPI_Waitall(4, send_reqs, MPI_STATUSES_IGNORE); 
delete [] send_reqs; 

Другой (и имхо лучше) вариантом было бы использовать MPI_Scatterv разбрасывать исходный буфер данных. Таким образом, вы даже можете сохранить клонирование частей матрицы изображений.

if (rank == 0) { 
    Mat mat = imread("/home/user/original.jpg", CV_LOAD_IMAGE_COLOR); 
    if (!mat.data) exit(-1); 

    int *send_counts = new int[size]; 
    int *displacements = new int[size]; 

    // The following calculations assume row-major storage 
    for (int i = 0; i < size; i++) { 
     send_counts[i] = displacements[i] = 0; 
    } 
    int idx = 1; 
    for (int c = 0; c < 512; c += 128) { 
     displacements[idx] = displacements[idx-1] + send_counts[idx-1]; 
     send_counts[idx] = 128 * 512 * 3; 
     idx++; 
    } 

    MPI_Scatterv(mat.data, send_counts, displacements, MPI_BYTE, 
       NULL, 0, MPI_BYTE, 0, MPI_COMM_WORLD); 

    delete [] send_counts; 
    delete [] displacements; 
} 
if (1 <= rank && rank <= 4) { 
    Mat test = Mat(512, 128, CV_8UC3); 
    MPI_Scatterv(NULL, NULL, NULL, MPI_BYTE, 
       test.data, 128 * 512 * 3, MPI_BYTE, 0, MPI_COMM_WORLD); 

    s << "/home/user/p" << rank << ".jpg"; 
    imwrite(s.str(), test); 
} 

Обратите внимание на то, как подготовлены аргументы MPI_Scatterv. Поскольку вы рассеиваете только 4 процесса MPI, установка определенных элементов send_counts[] в ноль позволяет программе правильно функционировать с более чем 5 процессами MPI. Кроме того, корень в исходном коде не отправляется самому себе, поэтому send_counts[0] должен быть равен нулю.

1

Проблема заключается в том, что вы не ждать до операции передачи завершается до матрица Mat разрушается. Используйте MPI_Send вместо MPI_Isend.

Если вы действительно хотите использовать неблокирующую связь, вам необходимо отслеживать все объекты MPI_Request и всех изображений Mat, пока передача не будет завершена.

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