MPI_Scatter - отправка столбцов 2D-массива - PullRequest
2 голосов
/ 01 апреля 2011

Я хочу отправить столбцы 2D-массива, каждый для отдельного процесса.Теперь у меня есть целый массив 2d, и я застрял с MPI_Scatter.Как отправить целые столбцы в виде поля?

Спасибо

редактировать:

У меня есть массив - плавать [100] [101]

, и я пыталсяотправить массив по:

float send;
MPI_Scatter ((void *)a, n, MPI_FLOAT,(void *)&send  , 1, MPI_INT,0, MPI_COMM_WORLD);

Edit2:

Я сделал новый type_vector:

               MPI_Datatype newtype;

               MPI_Type_vector(n,       /* # column elements */
                   1,           /* 1 column only */
                   n+1,         /* skip n+1 elements */
                   MPI_FLOAT,       /* elements are float */
                   &newtype);       /* MPI derived datatype */

               MPI_Type_commit(&newtype);

и теперь Iam пытается отправить его другим моим процессам.Матрица заполнена числами с плавающей запятой, моя матрица nx n + 1, для тестирования n = 5, поэтому это матрица 5 x 6. Какой вызов Scatter будет работать и какой подход я должен использовать со стороны других процессов?Я имею в виду, как получить данные, которые отправляются по Scatter?

Ответы [ 3 ]

6 голосов
/ 01 апреля 2011

Это очень похоже на этот вопрос: Как получить столбцы MPI_Gatherv из процессора, где каждый процесс может отправлять различное количество столбцов .Проблема в том, что столбцы не являются смежными в памяти, поэтому вам нужно поиграться.

Как всегда в случае с C, при отсутствии реальных многомерных массивов, вы должны быть немного осторожны с разметкой памяти.Я верю в C, это тот случай, когда статически объявленный массив, такой как

float a[nrows][ncols]

, будет непрерывным в памяти, так что вы должны быть в порядке на данный момент.Однако имейте в виду, что как только вы перейдете к динамическому распределению, это больше не будет иметь место;вам нужно было бы выделить все данные одновременно, чтобы убедиться, что вы получаете непрерывные данные, например,

float **floatalloc2d(int n, int m) {
    float *data = (float *)malloc(n*m*sizeof(float));
    float **array = (float **)calloc(n*sizeof(float *));
    for (int i=0; i<n; i++)
        array[i] = &(data[i*m]);

    return array;
}

float floatfree2d(float **array) {
    free(array[0]);
    free(array);
    return;
}

/* ... */
float **a;
nrows = 3;
ncols = 2;
a = floatalloc2d(nrows,ncols);

, но я думаю, что вы все в порядке.

Теперь, когда у вас естьВаш 2d массив так или иначе, вы должны создать свой тип.Тип, который вы описали, подходит, если вы просто отправляете один столбец;но хитрость здесь в том, что если вы отправляете несколько столбцов, каждый столбец начинается только на один поток после начала предыдущего, даже если сам столбец охватывает почти весь массив!Поэтому вам нужно переместить верхнюю границу типа, чтобы это работало:

       MPI_Datatype col, coltype;

       MPI_Type_vector(nrows,    
           1,                  
           ncols,         
           MPI_FLOAT,       
           &col);       

       MPI_Type_commit(&col);
       MPI_Type_create_resized(col, 0, 1*sizeof(float), &coltype);
       MPI_Type_commit(&coltype); 

будет делать то, что вы хотите.Обратите внимание, что процессы , получающие , будут иметь разные типы, чем процессы , отправляющие , потому что они хранят меньшее количество столбцов;так что шаг между элементами меньше.

Наконец, теперь вы можете сделать разброс,

MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
if (rank == 0) {
    a = floatalloc2d(nrows,ncols);
    sendptr = &(a[0][0]);
} else {
    sendptr = NULL;
}
int ncolsperproc = ncols/size;  /* we're assuming this divides evenly */
b = floatalloc(nrows, ncolsperproc);

MPI_Datatype acol, acoltype, bcol, bcoltype;

if (rank == 0) {
    MPI_Type_vector(nrows,    
               1,                  
               ncols,         
               MPI_FLOAT,       
               &acol);       

     MPI_Type_commit(&acol);
     MPI_Type_create_resized(acol, 0, 1*sizeof(float), &acoltype);
}
MPI_Type_vector(nrows,    
               1,                  
               ncolsperproc,         
               MPI_FLOAT,       
               &bcol);       

MPI_Type_commit(&bcol);
MPI_Type_create_resized(bcol, 0, 1*sizeof(float), &bcoltype);
MPI_Type_commit(&bcoltype);

MPI_Scatter (sendptr, ncolsperproc, acoltype, &(b[0][0]), ncolsperproc, bcoltype, 0, MPI_COMM_WORLD);
3 голосов
/ 01 апреля 2011

С этим не так много вещей, но ваша главная проблема - расположение памяти.В ячейке памяти, обозначенной a, нет ни одного float: есть только float*, которые указывают на различные массивы float в других местах памяти.Поскольку эти массивы не обязательно являются смежными, вы не можете использовать Scatter для них.

Самым простым решением было бы хранить вашу матрицу в одном массиве:

float a[100*101];

И заполните его в мажорном порядке.Затем просто Scatter, например, так:

MPI_Scatter(a, 100*101, MPI_FLOAT, send, 10*101, MPI_FLOAT, 0, MPI_COMM_WORLD);

Это предполагает, что вы разбрасываете между 10 процессами, и send определяется как float[10*101] в каждом процессе.Обратите внимание, что в размещенном вами коде аргументы 4-6 Scatter явно ошибочны.Если send является массивом, вам не нужно передавать &send (по той же причине, по которой вам не нужно передавать &a в первом аргументе), и вы хотите сопоставить число и типэлементы данных, которые вы получаете к тому, что вы отправляете.

0 голосов
/ 01 апреля 2011

Ну, Скаттер пытается отправить данные, которые он должен отправить в равных пропорциях. К сожалению, данные в C хранятся не по столбцам, а по строкам. Поэтому ваш вызов заставит Scatter взять n элементов, а затем отправить каждому процессу m = n / (число процессов) с плавающей точкой.

Общий подход к этой задаче - создание нового MPI-векторного типа данных (см. Функцию MPI_Type_vector), в котором вы сможете решить проблему строкового хранения данных в массивах C (поскольку вы можете определить шаг между к элементам в векторе, который будет в точности равным длине одной строки).

Я не использовал scatter с вектором таким образом, поэтому я не уверен, поможет ли это для вызова Scatter, но, по крайней мере, вы можете легко получить доступ к данным по столбцам. Тогда это был бы простой способ передать эти данные соответствующим процессам, используя цикл

...