2015-03-24 5 views
0

Я предполагаю, что мой вопрос имеет 2 части:C++ на куски

(1) Является ли это правильный подход, чтобы отправить различные куски массива для различных процессоров? Предположим, у меня есть n процессоры, чей ранг колеблется от 0 до n-1. У меня есть массив размером d. Я хочу разбить этот массив на k одинаковые куски. Предположите, что d делится на k. Я хочу отправить каждый из этих кусков процессору, чей ранг меньше k. Было бы легко, если бы я мог использовать что-то вроде MPI_Scatter, но эта функция посылает КАЖДЫМ ДРУГИМ процессорам, и я хочу отправить только определенное количество proc. Так что я сделал то, что у меня есть петля k итераций и do kMPI_Isend. Является ли это эффективным?

(2) Если да, то как мне разделить массив на куски? Там всегда легкий путь, который

int size = d/k; 
int buffs[k][size]; 

for (int rank = 0; rank < k; ++rank) 
{ 
    for (int i = 0; i < size ++i) 
     buffs[rank][i] = input[rank*size + i]; 
    MPI_Isend(&buffs[rank], size, MPI_INT, rank, 1, comm, &request); 
} 
+0

Не будет ли это переписывать 'buff' каждый раз через ваш внутренний цикл? Почему бы просто не отправить указатели на исходный массив? –

+0

Мой второй вопрос все еще стоит; почему вы беспокоитесь о копии? –

+0

Хороший вопрос! Это тоже часть моей первой части вопроса! Я спрашивал, было ли то, что я сделал, правильный подход ... похоже, что это не так. – 0x56794E

ответ

1

Что вы ищете MPI_Scatterv, который позволяет явно указать длину каждого блока и его положение относительно начала буфера. Если вы не хотите отправлять данные в определенные ряды, просто установить длину их кусков до 0:

int blen[n]; 
MPI_Aint displ[n]; 

for (int rank = 0; rank < n; rank++) 
{ 
    blen[rank] = (rank < k) ? size : 0; 
    displ[rank] = rank * size; 
} 

int myrank; 
MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 

MPI_Scatterv(input, blen, displ, MPI_INT, 
      mybuf, myrank < k ? size : 0, MPI_INT, 
      0, MPI_COMM_WORLD); 

Обратите внимание, что для rank >= k смещения будет работать мимо конца буфера. Все в порядке, поскольку длина блоков равна нулю для rank >= k, и никакие данные не будут доступны.

Что касается вашего первоначального подхода, он не переносится и может не всегда работать. Причина в том, что вы переписываете один и тот же дескриптор request, и вы никогда не дожидаетесь завершения отправки. Правильная реализация:

MPI_Request request[k]; 

for (int rank = 0; rank < k; ++rank) 
{ 
    MPI_Isend(&input[rank*size], size, MPI_INT, rank, 1, comm, &request[rank]); 
} 
MPI_Waitall(k, request, MPI_STATUSES_IGNORE); 

Наиболее оптимальная реализация будет использовать MPI_Scatter в subcommunicator:

MPI_Comm subcomm; 
MPI_Comm_split(MPI_COMM_WORLD, myrank < k ? 0 : MPI_UNDEFINED, myrank, 
       &subcomm); 
// Now there are k ranks in subcomm 
// Perform the scatter in the subcommunicator 
if (subcomm != MPI_COMM_NULL) 
    MPI_Scatter(input, size, MPI_INT, mybuf, size, MPI_INT, 0, subcomm); 

MPI_Comm_split вызова расщепляется MPI_COMM_WORLD и создает новый коммуникатор от всех оригинальных занимает меньше k. Он использует исходный ранг в качестве ключа для упорядочения рангов в новом коммуникаторе, поэтому ранг 0 в MPI_COMM_WORLD становится ранг 0 в subcomm. Так как MPI_Scatter часто работает лучше, чем MPI_Scatterv, это наиболее оптимальное решение.

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