2014-09-02 6 views
1

Я новичок в MPI. Я написал простой код для отображения матрицы с использованием нескольких процессов. Скажем, если у меня есть матрица 8x8 и запуск программы MPI с 4 процессами, то 1-й 2 строки будут напечатаны мой первый процесс, 2-й набор из 2-х строк будет напечатан 2-м потоком и так далее, разделив его в равной степени.Динамическое распределение памяти в MPI

#define S 8 

MPI_Status status; 

int main(int argc, char *argv[]) 
{ 
int numtasks, taskid; 
int i, j, k = 0; 

MPI_Init(&argc, &argv); 
MPI_Comm_rank(MPI_COMM_WORLD, &taskid); 
MPI_Comm_size(MPI_COMM_WORLD, &numtasks); 

int rows, offset, remainPart, orginalRows, height, width; 
int **a; 
// int a[S][S]; 

if(taskid == 0) 
{ 
    cout<<taskid<<endl; 
    height = width = S; 

    a = (int **)malloc(height*sizeof(int *)); 
    for(i=0; i<height; i++) 
     a[i] = (int *)malloc(width*sizeof(int)); 

    for(i=0; i<S; i++) 
     for(j=0; j<S; j++) 
      a[i][j] = ++k; 

    rows = S/numtasks; 
    offset = rows; 
    remainPart = S%numtasks; 

    cout<<"Num Rows : "<<rows<<endl; 

    for(i=1; i<numtasks; i++) 
     if(remainPart > 0) 
     { 
      orginalRows = rows; 
      rows++; 
      remainPart--; 

      MPI_Send(&offset, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&rows, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&width, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD); 

      offset += rows; 
      rows = orginalRows; 
     } 
     else 
     { 
      MPI_Send(&offset, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&rows, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&width, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD); 

      offset += rows; 
     } 

     //Processing 
     rows = S/numtasks; 
     for(i=0; i<rows; i++) 
     { 
      for(j=0; j<width; j++) 
       cout<<a[i][j]<<"\t"; 
      cout<<endl; 
     } 
}else 
{ 
    cout<<taskid<<endl; 

    MPI_Recv(&offset, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    MPI_Recv(&rows, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    MPI_Recv(&width, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    a = (int **)malloc(rows*sizeof(int *)); 
    for(i=0; i<rows; i++) 
     a[i] = (int *)malloc(width*sizeof(int)); 
    MPI_Recv(&a, rows*width, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    cout<<"Offset : "<<offset<<"\nRows : "<<rows<<"\nWidth : "<<width<<endl; 

    for(i=0; i<rows; i++) 
    { 
     for(j=0; j<width; j++) 
      cout<<a[i][j]<<"\t"; 
     cout<<endl; 
    } 
} 

getch(); 
MPI_Finalize(); 

return 0; 
} 

Это мой полный код, здесь я выделил память динамически для «а», в то время как печать [I] [J], под еще часть, я получаю сообщение об ошибке выполнения. Если изменить динамическое выделение памяти для статического как изменение Int ** а к Int а [N] [N] и удаление

a = (int **)malloc(rows*sizeof(int)); 
    for(i=0; i<rows; i++) 
     a[i] = (int *)malloc(width*sizeof(int)); 

она прекрасно работает.

+0

.... и что происходит при попытке динамического распределения памяти? В чем дело? Я не вижу ни одного вопросительного знака в вашем тексте (или я слепую?). – gurka

+1

Здесь много бесчисленных других вопросов о переполнении стека. Почему бы просто не использовать функцию поиска? –

+1

Вам нужно выделить память массива 1D. Похоже, ваш массив несмежен. – Jeff

ответ

7

Существует как минимум два способа динамического выделения двумерного массива.

Первый из них - символ @HRoid: каждая строка выделяется по одному. Посмотрите here для получения схемы.

Вторая предложенная @Claris, и это гарантирует, что данные смежны в памяти. Это требуется для многих операций MPI ... это также требуется библиотеками, такими как FFTW (2D быстрое преобразование Фурье) или Lapack (плотные матрицы для линейной алгебры). Ваша программа может потерпеть неудачу в

MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD); 

если S>1, эта программа будет пытаться отправить элементы, которые после окончания линии п ° offset ... Это может вызвать ошибку сегментации или неопределенное поведение.

Вы можете выделить ваш массив this way:

a = malloc(rows * sizeof(int *)); 
if(a==NULL){fprintf(stderr,"out of memory...i will fail\n");} 
int *t = malloc(rows * width * sizeof(int)); 
if(t==NULL){fprintf(stderr,"out of memory...i will fail\n");} 
for(i = 0; i < rows; ++i) 
    a[i] = &t[i * width]; 

Берегись: mallocdoes not initialize memory to 0!

Кажется, что вы хотите распространять 2D-массив по многим процессам. Посмотрите на MPI_Scatterv()here. Посмотрите также на this question.

Если вы хотите узнать больше о 2D-массивах и MPI, посмотрите here.

Вы можете найти базовый пример MPI_Scatterv here.

I изменено #define S 8 для #define SQUARE_SIZE 42. Всегда лучше давать описательные имена.

И вот рабочий код с использованием MPI_Scatterv()!

#include <mpi.h> 
#include <iostream> 
#include <cstdlib> 

using namespace std; 

#define SQUARE_SIZE 42 

MPI_Status status; 

int main(int argc, char *argv[]) 
{ 
    int numtasks, taskid; 
    int i, j, k = 0; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &taskid); 
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks); 

    int rows, offset, remainPart, orginalRows, height, width; 
    int **a; 

    height = width = SQUARE_SIZE; 

    //on rank 0, let's build a big mat of int 
    if(taskid == 0){ 
     a=new int*[height]; 
     int *t =new int[height * width]; 
     for(i = 0; i < height; ++i) 
      a[i] = &t[i * width]; 
     for(i=0; i<height; i++) 
      for(j=0; j<width; j++) 
       a[i][j] = ++k; 
    } 

    //for everyone, lets compute numbers of rows, numbers of int and displacements for everyone. Only 0 will use these arrays, but it's a practical way to get `rows` 
    int nbrows[numtasks]; 
    int sendcounts[numtasks]; 
    int displs[numtasks]; 
    displs[0]=0; 
    for(i=0;i<numtasks;i++){ 
     nbrows[i]=height/numtasks; 
     if(i<height%numtasks){ 
      nbrows[i]=nbrows[i]+1; 
     } 
     sendcounts[i]=nbrows[i]*width; 
     if(i>0){ 
      displs[i]=displs[i-1]+sendcounts[i-1]; 
     } 
    } 
    rows=nbrows[taskid]; 

    //scattering operation. 
    //The case of the root is particular, since the communication is not to be done...Hence, the flag MPI_IN_PLACE is used. 
    if(taskid==0){ 
     MPI_Scatterv(&a[0][0],sendcounts,displs,MPI_INT,MPI_IN_PLACE,0,MPI_INT,0,MPI_COMM_WORLD); 
    }else{ 
     //allocation of memory for the piece of mat on the other nodes. 
     a=new int*[rows]; 
     int *t =new int[rows * width]; 
     for(i = 0; i < rows; ++i) 
      a[i] = &t[i * width]; 

     MPI_Scatterv(NULL,sendcounts,displs,MPI_INT,&a[0][0],rows*width,MPI_INT,0,MPI_COMM_WORLD); 
    } 
    //printing, one proc at a time 
    if(taskid>0){ 
     MPI_Status status; 
     MPI_Recv(NULL,0,MPI_INT,taskid-1,0,MPI_COMM_WORLD,&status); 
    } 
    cout<<"rank"<< taskid<<" Rows : "<<rows<<" Width : "<<width<<endl; 

    for(i=0; i<rows; i++) 
    { 
     for(j=0; j<width; j++) 
      cout<<a[i][j]<<"\t"; 
     cout<<endl; 
    } 
    if(taskid<numtasks-1){ 
     MPI_Send(NULL,0,MPI_INT,taskid+1,0,MPI_COMM_WORLD); 
    } 

    //freeing the memory ! 

    delete[] a[0]; 
    delete[] a; 

    MPI_Finalize(); 

    return 0; 
} 

Для компиляции: mpiCC main.cpp -o main

Для запуска: mpiexec -np 3 main

+0

Я удалил свой ответ, поскольку ваш вопрос более уместен. – HRold

+0

@francis, я выделил данные так, как вы сказали. Тем не менее, я получаю ту же ошибку. Можете ли вы помочь мне снова, пожалуйста. Теперь я собираюсь попробовать MPI_Scatterv. Благодарю. – suraj1291993

1

Этот код выглядит ужасно подозрительным.

a = (int **)malloc(rows*sizeof(int)); 
for(i=0; i<rows; i++) 
    a[i] = (int *)malloc(width*sizeof(int)); 
MPI_Recv(&a, rows*width, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 

Ваше создание массива int ** и правильное распределение, но затем вы не передаете отдельные указатели. MPI_Recv ожидает int * в качестве аргумента, не так ли?

Обратите внимание, что при выполнении int [] [] выделенная память будет смежной. Когда вы делаете malloc, вы должны ожидать нескончаемые блоки памяти.

Простое решение может состоять в том, чтобы просто сделать a = (int**) malloc (big), а затем проиндексировать его с большим распределением памяти.

+0

Массив неправильно распределен, malloc первого уровня должен использовать 'sizeof (int *)' not 'sizeof (int)'. – HRold

+0

@HRold, я изменил то, что вы сказали, спасибо ... Еще не работает. Можете ли вы помочь мне снова, пожалуйста. – suraj1291993

+0

@ suraj1291993 Да, можете ли вы дать прототип функции 'MPI_Recv()'? – HRold

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