source

MPI를 사용하여 C에서 2D 배열 블록 전송

goodcode 2022. 8. 15. 21:10
반응형

MPI를 사용하여 C에서 2D 배열 블록 전송

2D 어레이 블록을 다른 프로세서로 전송하려면 어떻게 해야 합니까?2D 어레이 크기가 400x400이라고 가정하면 크기가 100x100인 블록을 다른 프로세서로 보내고 싶습니다.은 각 프로세서가 의 개별 그 를 첫 번째 입니다.
MPI를 사용하다

우선, 일반적으로는, 「마스터」프로세스로부터 대량의 데이터를 수집해 버리는 것은 그다지 하고 싶지 않습니다.통상, 각 태스크는 그 퍼즐의 일부에 집중해, 데이터 전체를 「글로벌 뷰」로 표시할 필요가 없는 것을 목표로 합니다.필요에 따라서, scalability와 문제의 사이즈를 제한할 수 있습니다.I/O를 위해 이 작업을 수행할 경우, 한 프로세스가 데이터를 읽고, 산란시킨 다음, 쓰기 위해 데이터를 다시 수집하면 최종적으로 MPI-IO를 조사하게 됩니다.

단, MPI는 메모리에서 임의의 데이터를 꺼내 프로세서 세트로 분산/수집하는 매우 좋은 방법이 있습니다.유감스럽게도 MPI의 개념은 MPI 유형, 익스텐트 및 집합 운영 등 상당히 많이 필요합니다.MPI_Type_create_subarray와 MPI_Gather라는 질문에 대한 답변에는 많은 기본 아이디어가 논의되어 있습니다.

업데이트 - 냉정하게 볼 때, 이것은 많은 코드이며 설명이 많지 않습니다.조금 더 확대해 보겠습니다.

태스크 0에 포함된 1d 정수 글로벌 어레이를 여러 MPI 태스크에 배포하여 각 태스크가 로컬 어레이에 포함되도록 합니다.작업이 은 4개입니다.[01234567]태스크 0은 4개의 메시지(하나 포함)를 전송하여 이 메시지를 배포할 수 있습니다.재어셈블리가 필요한 경우 4개의 메시지를 수신하여 번들링할 수 있습니다.다만, 대량의 프로세스에서는, 분명히 시간이 걸립니다.이러한 종류의 작업(산포/수집 작업)에 최적화된 루틴이 있습니다. 이 할 수 . 1D는 1D로 하다.

int global[8];   /* only task 0 has this */
int local[2];    /* everyone has this */
const int root = 0;   /* the processor with the initial global data */

if (rank == root) {
   for (int i=0; i<7; i++) global[i] = i;
}

MPI_Scatter(global, 2, MPI_INT,      /* send everyone 2 ints from global */
            local,  2, MPI_INT,      /* each proc receives 2 ints into local */
            root, MPI_COMM_WORLD);   /* sending process is root, all procs in */
                                     /* MPI_COMM_WORLD participate */

이 후 프로세서의 데이터는 다음과 같습니다.

task 0:  local:[01]  global: [01234567]
task 1:  local:[23]  global: [garbage-]
task 2:  local:[45]  global: [garbage-]
task 3:  local:[67]  global: [garbage-]

즉, scatter 조작은 글로벌어레이를 취득하여 연속된2-int 청크를 모든 프로세서에 송신합니다.

어레이를 재구성하려면MPI_Gather()동작은 똑같지만 역방향으로 동작합니다.

for (int i=0; i<2; i++) 
   local[i] = local[i] + rank;

MPI_Gather(local,  2, MPI_INT,      /* everyone sends 2 ints from local */
           global, 2, MPI_INT,      /* root receives 2 ints each proc into global */
           root, MPI_COMM_WORLD);   /* recv'ing process is root, all procs in */
                                    /* MPI_COMM_WORLD participate */

그리고 이제 데이터는

task 0:  local:[01]  global: [0134679a]
task 1:  local:[34]  global: [garbage-]
task 2:  local:[67]  global: [garbage-]
task 3:  local:[9a]  global: [garbage-]

Gather는 모든 데이터를 되돌립니다.여기서 a는 10입니다.이 예를 시작할 때 포맷을 충분히 주의 깊게 하지 않았기 때문입니다.

데이터 포인트의 수가 프로세스 수를 균등하게 나누지 않고 각 프로세스에 다른 수의 항목을 보내야 하는 경우 어떻게 됩니까?그럼 일반화된 버전의 산란이 필요하겠군MPI_Scatterv()각 프로세서의 카운트와 변위량을 지정할 수 있습니다.글로벌 어레이에서 데이터 조각이 시작되는 위치입니다.예를 들어, 여러 가지 캐릭터가 있다고 칩시다.[abcdefghi]모든 프로세스에 2글자를 할당하려고 했는데 마지막 3글자를 제외한 나머지 2글자를 할당하려고 했습니다.그럼 당신은

char global[9];   /* only task 0 has this */
char local[3]={'-','-','-'};    /* everyone has this */
int  mynum;                     /* how many items */
const int root = 0;   /* the processor with the initial global data */

if (rank == 0) {
   for (int i=0; i<8; i++) global[i] = 'a'+i;
}

int counts[4] = {2,2,2,3};   /* how many pieces of data everyone has */
mynum = counts[rank];
int displs[4] = {0,2,4,6};   /* the starting point of everyone's data */
                             /* in the global array */

MPI_Scatterv(global, counts, displs, /* proc i gets counts[i] pts from displs[i] */
            MPI_INT,      
            local, mynum, MPI_INT;   /* I'm receiving mynum MPI_INTs into local */
            root, MPI_COMM_WORLD);

이제 데이터는

task 0:  local:[ab-]  global: [abcdefghi]
task 1:  local:[cd-]  global: [garbage--]
task 2:  local:[ef-]  global: [garbage--]
task 3:  local:[ghi]  global: [garbage--]

이제 scatv를 사용하여 불규칙한 양의 데이터를 배포했습니다.각 경우의 변위는 배열 시작부터 2*랭크(문자 단위로 측정됩니다. 변위는 산란 또는 수집용으로 수신된 유형의 단위입니다. 일반적으로 바이트 단위 등은 아닙니다.)이며 카운트는 {2,2,3,}입니다.3글자를 원하는 첫 번째 프로세서라면 counts={3,2,2}로 설정했을 것이고, 변위는 {0,3,5,7}이 되었을 것입니다.Gatherv는 다시 동일하게 동작하지만, 반대로 동작합니다.수 및 디스플레이 어레이는 동일하게 유지됩니다.

2D에서는 좀 더 까다롭습니다.2D 어레이의 2D 서브록을 송신하는 경우, 송신하는 데이터는 더 이상 연속되지 않습니다.6x6 어레이의 3x3 서브블록을 4개의 프로세서에 송신(예를 들어)하는 경우, 송신하는 데이터에 구멍이 있습니다.

2D Array

   ---------
   |000|111|
   |000|111|
   |000|111|
   |---+---|
   |222|333|
   |222|333|
   |222|333|
   ---------

Actual layout in memory

   [000111000111000111222333222333222333]

(모든 고성능 컴퓨팅은 메모리의 데이터 레이아웃을 이해하는 것으로 귀결됩니다.)

작업 1에 "1"로 표시된 데이터를 전송하려면 세 개의 값을 건너뛰고, 세 개의 값을 보내고, 세 개의 값을 건너뛰고, 세 개의 값을 보내고, 세 개의 값을 건너뛰고, 세 개의 값을 보내야 합니다.두 번째 문제는 서브영역이 정지하고 시작되는 곳입니다.영역 "1"은 영역 "0"이 정지하는 곳에서 시작되지 않습니다.영역 "0"의 마지막 요소 뒤에 메모리 내의 다음 위치는 영역 "1"을 통과하는 중간 지점입니다.

우선 첫 번째 레이아웃 문제인 송신하는 데이터만을 추출하는 방법에 대해 설명하겠습니다.에 "수 하면 "0" 지역 데이터를 "0"으로 수 .또한 신중하게 계획하면 콜을 할 수 있는 방법으로도 할 수 있습니다.MPI_Scatter결과를 보고합니다.그러나 전체 주요 데이터 구조를 그런 식으로 바꿀 필요는 없습니다.

지금까지 사용한 MPI 데이터 타입은 모두 단순한 것입니다.MPI_INT는 4바이트를 연속해서 지정합니다.그러나 MPI를 사용하면 메모리에서 임의로 복잡한 데이터 레이아웃을 설명하는 고유한 데이터 유형을 생성할 수 있습니다.이 경우 - 어레이의 직사각형 하위 영역 - 특정 요구가 있을 정도로 일반적입니다.위에서 설명한 2차원 케이스는

    MPI_Datatype newtype;
    int sizes[2]    = {6,6};  /* size of global array */
    int subsizes[2] = {3,3};  /* size of sub-region */
    int starts[2]   = {0,0};  /* let's say we're looking at region "0",
                                 which begins at index [0,0] */

    MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_INT, &newtype);
    MPI_Type_commit(&newtype);

이것에 의해, 글로벌 어레이로부터 영역 「0」만을 선택하는 타입이 작성됩니다.그 데이터만을 다른 프로세서로 송신할 수 있습니다.

    MPI_Send(&(global[0][0]), 1, newtype, dest, tag, MPI_COMM_WORLD);  /* region "0" */

수신 프로세스가 로컬 어레이로 수신할 수 있습니다.수신 프로세스가 3x3 어레이로만 수신되는 경우 수신 프로세스가 수신되는 대상을newtype; 더 이상 메모리 레이아웃을 설명하지 않습니다.=의 정수 아, 3*3 = 9개의 을 받는 입니다.

    MPI_Recv(&(local[0][0]), 3*3, MPI_INT, 0, tag, MPI_COMM_WORLD);

수 .start다른 블록에 대해서는, 또는 특정 블록의 시작점에 송신하는 것만으로, 다음의 처리를 실시합니다.

    MPI_Send(&(global[0][3]), 1, newtype, dest, tag, MPI_COMM_WORLD);  /* region "1" */
    MPI_Send(&(global[3][0]), 1, newtype, dest, tag, MPI_COMM_WORLD);  /* region "2" */
    MPI_Send(&(global[3][3]), 1, newtype, dest, tag, MPI_COMM_WORLD);  /* region "3" */

및 되어 「」는 「」입니다.&(global[0][0]) ★★★★★★★★★★★★★★★★★」&(local[0][0]) *global ★★★★★★★★★★★★★★★★★」*local6*6 및 3*3 。이는 다이내믹 멀티D 어레이를 할당하는 일반적인 방법으로는 보증되지 않습니다.이 방법은 다음과 같습니다.

이제 하위 영역을 지정하는 방법을 이해했습니다. 산포/수집 작업을 사용하기 전에 검토해야 할 사항은 하나뿐입니다. 을 사용하다'냥쓸 use use use use use use를 사용할 수 .MPI_Scatter()(또는 scatv)는 아직 이러한 유형의 데이터 전송은 16개의 정수의 범위를 가지기 때문에 시작 후 16개의 정수로 끝납니다. 즉, 다음 블록이 시작되는 부분과 제대로 정렬되지 않기 때문에 산포만 사용할 수 없습니다. 데이터 전송을 다음 프로세서로 시작하기 위해 잘못된 위치를 선택할 수 있습니다.

론, 리, 우, 우, 우, 있, 있, 있, 다, of, 다, of, 다, of, of, of, of, ,MPI_Scatterv()직접 변위를 지정합니다.변위가 송신형 크기 단위라는 점만 제외하면 이 작업에는 도움이 되지 않습니다.multi록 、 [ 0 , 3, 18 , 21 ]정수 배수로 시멘트를 합니다.

이 문제를 해결하기 위해 MPI를 사용하면 이러한 계산을 위해 유형의 범위를 설정할 수 있습니다.유형을 잘라내는 것이 아니라 마지막 요소가 주어진 다음 요소의 시작 위치를 파악하는 데 사용됩니다.이러한 구멍이 있는 타입의 경우는, 메모리내의 거리보다 작은 범위로 설정하는 것이 편리합니다.

우리에게 편리한 범위라면 무엇이든 설정할 수 있습니다.익스텐트 1을 정수로 한 다음 정수 단위로 변위를 설정할 수 있습니다.그러나 이 경우 범위를 3개의 정수(하위 행 크기)로 설정하고 블록 "1"은 블록 "0" 바로 뒤에 시작하고 블록 "3"은 블록 "2" 바로 뒤에 시작합니다.안타깝게도 블록 2에서 블록 3으로 점프할 때처럼 잘 작동하지 않지만 어쩔 수 없습니다.

이 경우 서브블록을 분산시키려면 다음 작업을 수행합니다.

    MPI_Datatype type, resizedtype;
    int sizes[2]    = {6,6};  /* size of global array */
    int subsizes[2] = {3,3};  /* size of sub-region */
    int starts[2]   = {0,0};  /* let's say we're looking at region "0",
                                 which begins at index [0,0] */

    /* as before */
    MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_INT, &type);  
    /* change the extent of the type */
    MPI_Type_create_resized(type, 0, 3*sizeof(int), &resizedtype);
    MPI_Type_commit(&resizedtype);

여기서는 이전과 동일한 블록 유형을 생성했지만 크기를 조정했습니다. 유형 "시작"(0)은 변경하지 않았지만 "끝"(3ints)은 변경했습니다.얘기 안 , ''가 '우리'가 '우리 '우리'가 아니라 '우리'가 '우리'가 ''가MPI_Type_commit는 유형을 사용할 수 있어야 합니다.단, 실제로 사용하는 최종 타입만 커밋하면 됩니다.중간 단계는 커밋하지 않습니다.은 you 다 you you youMPI_Type_free

마지막으로 블록을 분산할 수 있습니다.상기의 데이터 조작은 조금 복잡하지만 처리가 완료되면 이전과 같은 상태가 됩니다.

int counts[4] = {1,1,1,1};   /* how many pieces of data everyone has, in units of blocks */
int displs[4] = {0,1,6,7};   /* the starting point of everyone's data */
                             /* in the global array, in block extents */

MPI_Scatterv(global, counts, displs, /* proc i gets counts[i] types from displs[i] */
            resizedtype,      
            local, 3*3, MPI_INT;   /* I'm receiving 3*3 MPI_INTs into local */
            root, MPI_COMM_WORLD);

이것으로 산란형, 개더형, MPI유래형 등을 조금 둘러보고 완료했습니다.

문자 배열이 있는 수집 및 분산 작업을 모두 보여주는 코드 예를 다음에 나타냅니다.프로그램 실행:

$ mpirun -n 4 ./gathervarray
Global array is:
0123456789
3456789012
6789012345
9012345678
2345678901
5678901234
8901234567
1234567890
4567890123
7890123456
Local process on rank 0 is:
|01234|
|34567|
|67890|
|90123|
|23456|
Local process on rank 1 is:
|56789|
|89012|
|12345|
|45678|
|78901|
Local process on rank 2 is:
|56789|
|89012|
|12345|
|45678|
|78901|
Local process on rank 3 is:
|01234|
|34567|
|67890|
|90123|
|23456|
Processed grid:
AAAAABBBBB
AAAAABBBBB
AAAAABBBBB
AAAAABBBBB
AAAAABBBBB
CCCCCDDDDD
CCCCCDDDDD
CCCCCDDDDD
CCCCCDDDDD
CCCCCDDDDD

코드가 따라옵니다.

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "mpi.h"

int malloc2dchar(char ***array, int n, int m) {

    /* allocate the n*m contiguous items */
    char *p = (char *)malloc(n*m*sizeof(char));
    if (!p) return -1;

    /* allocate the row pointers into the memory */
    (*array) = (char **)malloc(n*sizeof(char*));
    if (!(*array)) {
       free(p);
       return -1;
    }

    /* set up the pointers into the contiguous memory */
    for (int i=0; i<n; i++)
       (*array)[i] = &(p[i*m]);

    return 0;
}

int free2dchar(char ***array) {
    /* free the memory - the first element of the array is at the start */
    free(&((*array)[0][0]));

    /* free the pointers into the memory */
    free(*array);

    return 0;
}

int main(int argc, char **argv) {
    char **global, **local;
    const int gridsize=10; // size of grid
    const int procgridsize=2;  // size of process grid
    int rank, size;        // rank of current process and no. of processes

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


    if (size != procgridsize*procgridsize) {
        fprintf(stderr,"%s: Only works with np=%d for now\n", argv[0], procgridsize);
        MPI_Abort(MPI_COMM_WORLD,1);
    }


    if (rank == 0) {
        /* fill in the array, and print it */
        malloc2dchar(&global, gridsize, gridsize);
        for (int i=0; i<gridsize; i++) {
            for (int j=0; j<gridsize; j++)
                global[i][j] = '0'+(3*i+j)%10;
        }


        printf("Global array is:\n");
        for (int i=0; i<gridsize; i++) {
            for (int j=0; j<gridsize; j++)
                putchar(global[i][j]);

            printf("\n");
        }
    }

    /* create the local array which we'll process */
    malloc2dchar(&local, gridsize/procgridsize, gridsize/procgridsize);

    /* create a datatype to describe the subarrays of the global array */

    int sizes[2]    = {gridsize, gridsize};         /* global size */
    int subsizes[2] = {gridsize/procgridsize, gridsize/procgridsize};     /* local size */
    int starts[2]   = {0,0};                        /* where this one starts */
    MPI_Datatype type, subarrtype;
    MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_CHAR, &type);
    MPI_Type_create_resized(type, 0, gridsize/procgridsize*sizeof(char), &subarrtype);
    MPI_Type_commit(&subarrtype);

    char *globalptr=NULL;
    if (rank == 0) globalptr = &(global[0][0]);

    /* scatter the array to all processors */
    int sendcounts[procgridsize*procgridsize];
    int displs[procgridsize*procgridsize];

    if (rank == 0) {
        for (int i=0; i<procgridsize*procgridsize; i++) sendcounts[i] = 1;
        int disp = 0;
        for (int i=0; i<procgridsize; i++) {
            for (int j=0; j<procgridsize; j++) {
                displs[i*procgridsize+j] = disp;
                disp += 1;
            }
            disp += ((gridsize/procgridsize)-1)*procgridsize;
        }
    }


    MPI_Scatterv(globalptr, sendcounts, displs, subarrtype, &(local[0][0]),
                 gridsize*gridsize/(procgridsize*procgridsize), MPI_CHAR,
                 0, MPI_COMM_WORLD);

    /* now all processors print their local data: */

    for (int p=0; p<size; p++) {
        if (rank == p) {
            printf("Local process on rank %d is:\n", rank);
            for (int i=0; i<gridsize/procgridsize; i++) {
                putchar('|');
                for (int j=0; j<gridsize/procgridsize; j++) {
                    putchar(local[i][j]);
                }
                printf("|\n");
            }
        }
        MPI_Barrier(MPI_COMM_WORLD);
    }

    /* now each processor has its local array, and can process it */
    for (int i=0; i<gridsize/procgridsize; i++) {
        for (int j=0; j<gridsize/procgridsize; j++) {
            local[i][j] = 'A' + rank;
        }
    }

    /* it all goes back to process 0 */
    MPI_Gatherv(&(local[0][0]), gridsize*gridsize/(procgridsize*procgridsize),  MPI_CHAR,
                 globalptr, sendcounts, displs, subarrtype,
                 0, MPI_COMM_WORLD);

    /* don't need the local data anymore */
    free2dchar(&local);

    /* or the MPI data type */
    MPI_Type_free(&subarrtype);

    if (rank == 0) {
        printf("Processed grid:\n");
        for (int i=0; i<gridsize; i++) {
            for (int j=0; j<gridsize; j++) {
                putchar(global[i][j]);
            }
            printf("\n");
        }

        free2dchar(&global);
    }


    MPI_Finalize();

    return 0;
}

그런 식으로 확인하는 게 더 쉬웠을 뿐이에요.

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "mpi.h"

/*
 This is a version with integers, rather than char arrays, presented in this
 very good answer: http://stackoverflow.com/a/9271753/2411320
 It will initialize the 2D array, scatter it, increase every value by 1 and then gather it back.
*/

int malloc2D(int ***array, int n, int m) {
    int i;
    /* allocate the n*m contiguous items */
    int *p = malloc(n*m*sizeof(int));
    if (!p) return -1;

    /* allocate the row pointers into the memory */
    (*array) = malloc(n*sizeof(int*));
    if (!(*array)) {
       free(p);
       return -1;
    }

    /* set up the pointers into the contiguous memory */
    for (i=0; i<n; i++)
       (*array)[i] = &(p[i*m]);

    return 0;
}

int free2D(int ***array) {
    /* free the memory - the first element of the array is at the start */
    free(&((*array)[0][0]));

    /* free the pointers into the memory */
    free(*array);

    return 0;
}

int main(int argc, char **argv) {
    int **global, **local;
    const int gridsize=4; // size of grid
    const int procgridsize=2;  // size of process grid
    int rank, size;        // rank of current process and no. of processes
    int i, j, p;

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


    if (size != procgridsize*procgridsize) {
        fprintf(stderr,"%s: Only works with np=%d for now\n", argv[0], procgridsize);
        MPI_Abort(MPI_COMM_WORLD,1);
    }


    if (rank == 0) {
        /* fill in the array, and print it */
        malloc2D(&global, gridsize, gridsize);
        int counter = 0;
        for (i=0; i<gridsize; i++) {
            for (j=0; j<gridsize; j++)
                global[i][j] = ++counter;
        }


        printf("Global array is:\n");
        for (i=0; i<gridsize; i++) {
            for (j=0; j<gridsize; j++) {
                printf("%2d ", global[i][j]);
            }
            printf("\n");
        }
    }
    //return;

    /* create the local array which we'll process */
    malloc2D(&local, gridsize/procgridsize, gridsize/procgridsize);

    /* create a datatype to describe the subarrays of the global array */
    int sizes[2]    = {gridsize, gridsize};         /* global size */
    int subsizes[2] = {gridsize/procgridsize, gridsize/procgridsize};     /* local size */
    int starts[2]   = {0,0};                        /* where this one starts */
    MPI_Datatype type, subarrtype;
    MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_INT, &type);
    MPI_Type_create_resized(type, 0, gridsize/procgridsize*sizeof(int), &subarrtype);
    MPI_Type_commit(&subarrtype);

    int *globalptr=NULL;
    if (rank == 0)
        globalptr = &(global[0][0]);

    /* scatter the array to all processors */
    int sendcounts[procgridsize*procgridsize];
    int displs[procgridsize*procgridsize];

    if (rank == 0) {
        for (i=0; i<procgridsize*procgridsize; i++)
            sendcounts[i] = 1;
        int disp = 0;
        for (i=0; i<procgridsize; i++) {
            for (j=0; j<procgridsize; j++) {
                displs[i*procgridsize+j] = disp;
                disp += 1;
            }
            disp += ((gridsize/procgridsize)-1)*procgridsize;
        }
    }


    MPI_Scatterv(globalptr, sendcounts, displs, subarrtype, &(local[0][0]),
                 gridsize*gridsize/(procgridsize*procgridsize), MPI_INT,
                 0, MPI_COMM_WORLD);

    /* now all processors print their local data: */

    for (p=0; p<size; p++) {
        if (rank == p) {
            printf("Local process on rank %d is:\n", rank);
            for (i=0; i<gridsize/procgridsize; i++) {
                putchar('|');
                for (j=0; j<gridsize/procgridsize; j++) {
                    printf("%2d ", local[i][j]);
                }
                printf("|\n");
            }
        }
        MPI_Barrier(MPI_COMM_WORLD);
    }

    /* now each processor has its local array, and can process it */
    for (i=0; i<gridsize/procgridsize; i++) {
        for (j=0; j<gridsize/procgridsize; j++) {
            local[i][j] += 1; // increase by one the value
        }
    }

    /* it all goes back to process 0 */
    MPI_Gatherv(&(local[0][0]), gridsize*gridsize/(procgridsize*procgridsize),  MPI_INT,
                 globalptr, sendcounts, displs, subarrtype,
                 0, MPI_COMM_WORLD);

    /* don't need the local data anymore */
    free2D(&local);

    /* or the MPI data type */
    MPI_Type_free(&subarrtype);

    if (rank == 0) {
        printf("Processed grid:\n");
        for (i=0; i<gridsize; i++) {
            for (j=0; j<gridsize; j++) {
                printf("%2d ", global[i][j]);
            }
            printf("\n");
        }

        free2D(&global);
    }


    MPI_Finalize();

    return 0;
}

출력:

linux16:>mpicc -o main main.c
linux16:>mpiexec -n 4 main Global array is:
 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15 16
Local process on rank 0 is:
| 1  2 |
| 5  6 |
Local process on rank 1 is:
| 3  4 |
| 7  8 |
Local process on rank 2 is:
| 9 10 |
|13 14 |
Local process on rank 3 is:
|11 12 |
|15 16 |
Processed grid:
 2  3  4  5
 6  7  8  9
10 11 12 13
14 15 16 17

언급URL : https://stackoverflow.com/questions/9269399/sending-blocks-of-2d-array-in-c-using-mpi

반응형