0

我正在做一个导入 32x32 或 64x64 PBM 图像文件的项目。示例如下:

P1
# CREATOR: GIMP PNM Filter Version 1.1
32 32
01111110000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000001000000000000
00000000000001100000000000000000
00001100000000100011100000000000
00001100000000000000000000000000
00000011000000000000000000000000
00000011000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000011100000
01000101001000000000000000000000
01000101010000011100000000000000
01000101100000111000000000000000
01000101010000000000000000000000
01000101001000000000000000000000
00111001001000000000000001000000
00000000000000000000000001000000
00000000000000000000000001000000
00000000000000000000000000000000
00000000010000000000000000000000
00000000001000000000000000000000
00000000111000000000000000000000
00000000000000000000000110000000
00000000000000000000001001000000
00110000000000000000000110000000
01100000000000000110000000001000
00100000000000000110000000001100
00000000000000011000000000001100
00000000000000011000000000000100
00000000000000000000000000000000

这被读入一维数组并按顺序处理。我试图将一维数组以 4x4 模式分解为多个数组。一旦分成“块”,临时较小的阵列将分布到多个处理元件。在处理完每个较小的块后,“块”将被发送回主节点以进行重组。

这是以顺序方式工作的完整代码:

/*  life.c

    Play Conway's Game of Life

    Reads a P1 file in, outputs a P1 file.

    Does as many timesteps as stated on the command line.

    Uses a classic 1-element fake zone internally.

    Jan. 30, 2013 by H. Dietz
*/

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


unsigned char *
read_P1(int *xdim, int *ydim)
{
    register int c, x, y;
    register unsigned char *p;

    if ((c = getchar()) != 'P') {
pbm_bad:
        fprintf(stderr, "Bad PBM input\n");
        exit(1);
    }
    if ((c = getchar()) != '1') goto pbm_bad;
    c = getchar();

#define Eat_Space \
    while ((c == ' ') || \
           (c == '\t') || \
           (c == '\n') || \
           (c == '\r') || \
           (c == '#')) { \
        if (c == '#') while ((c = getchar()) != '\n') ; \
        c = getchar(); \
    }

    Eat_Space;      /* Eat white space and comments */

#define Get_Number(n) \
    { \
        if ((c < '0') || (c > '9')) goto pbm_bad; \
 \
        n = (c - '0'); \
        c = getchar(); \
        while ((c >= '0') && (c <= '9')) { \
            n *= 10; \
            n += (c - '0'); \
            c = getchar(); \
        } \
    }

    Get_Number(*xdim);  /* Get image width */

    Eat_Space;      /* Eat white space and comments */
    Get_Number(*ydim);  /* Get image height */

    p = ((unsigned char *)
         calloc(((*xdim + 2) * (*ydim + 2)),
            sizeof(unsigned char)));
    if (p == 0) goto pbm_bad;

    Eat_Space;

    for (y=0; y<*ydim; ++y) {
        for (x=0; x<*xdim; ++x) {
            Eat_Space;
            switch (c) {
            case '1':   p[x+1+((y+1)*(*xdim+2))] = 1; break;
            case '0':   /* 0 from calloc() */ break;
            default:    goto pbm_bad;
            }
            c = getchar();
        }
    }

    return(p);
}

#undef  Eat_Space
#undef  Get_Number


write_P1(register int xdim,
register int ydim,
register unsigned char *p)
{
    register int x, y, pos = 0;

    printf("P1\n"
           "# CREATOR: P1IO\n"
           "%d %d\n",
           xdim,
           ydim);

    for (y=0; y<ydim; ++y) {
        for (x=0; x<xdim; ++x) {
            int c = "01"[ p[x+1+((y+1)*(xdim+2))] != 0 ];
            putchar(c);

            /* Keep lines even matrices */
            if ( (++pos)%xdim == 0) {
                putchar('\n');
            }
        }
    }
    putchar('\n');
}


int main(int argc, char **argv)
{
    if(MPI_Init(&argc, &argv) != MPI_SUCCESS){
        exit(1);
    }

    int xdim, ydim;
    int iproc, nproc;
    register unsigned char *p, *q, *masterP;
    register int x, y, i, j, t, divisions, timesteps;

    divisions = 4;

    MPI_Comm_size(MPI_COMM_WORLD, &nproc); //nproc = number of PE
    MPI_Comm_rank(MPI_COMM_WORLD, &iproc); //iproc = position out of nproc

    if (argc != 2) {
        fprintf(stderr, "Usage: %s timesteps\n", argv[0]);
        exit(2);
    }
    timesteps = atoi(argv[1]);


    /* Carve p into 4x4 and send to 15 processing elements. PE0 will
    handle one chunk on its own */
    //if(iproc == 0){
        int masterx, mastery;
        /* Read the initial state image */
        masterP = read_P1(&masterx, &mastery);
        xdim = (masterx/divisions);
        ydim = (mastery/divisions);


        /* Make a temporary array to send each chunk of the image */
        p = ((unsigned char *)calloc((((xdim)+2) * ((ydim)+2)), 
            sizeof(unsigned char)));
        if (p == 0) {
        fprintf(stderr, "Calloc failed\n");
        exit(3);
        }

        printf("Check master P\n");
        write_P1(masterx, mastery, masterP);


        int loopx , loopy;
        int cnt = 0;
        for(loopy = 0; loopy < divisions; ++loopy){
            for(loopx = 0; loopx < divisions; ++loopx){
                x=1;
                //Fill p
                for (j=(loopy*ydim)+1; j<((loopy+1)*ydim+2); ++j){
                    for( i=(loopx*xdim)+1; i<((loopx+1)*xdim+2); ++i){
                        //printf("j: %d i: %d\n",j,i);
                        p[x]=masterP[i+(loopy*j)+1];
                        printf("%d",p[x]);
                        x++;
                    }
                }
                //Print P contents
                printf("\nIteration Y:%d X:%d\n",loopy, loopx);
                write_P1(xdim, ydim, p);

            }
        }


        //MPI_Send(p, sizeof(temp), MPI_UNSIGNED_CHAR, pe_num, 0, MPI_COMM_WORLD);
        //++pe_num;

    //}/* End IProc 0's business */


    /* Make a target image (with blank fake zone) */
    q = ((unsigned char *)
         calloc(((xdim + 2) * (ydim + 2)),
            sizeof(unsigned char)));
    if (q == 0) {
        fprintf(stderr, "Calloc failed\n");
        exit(3);
    }

    /* Iterate over the timesteps */
    for (t=0; t<timesteps; ++t) {
#ifdef  VERBOSE
        fprintf(stderr, "Timestep %d...\n", t);
#endif

        for (y=0; y<ydim; ++y) {
            for (x=0; x<xdim; ++x) {

#define FAKE(P, X, Y) P[((X)+1)+(((Y)+1)*(xdim+2))]

                register int live = FAKE(p, x-1, y-1) +
                            FAKE(p, x, y-1) +
                            FAKE(p, x+1, y-1) +
                            FAKE(p, x-1, y) +
                            FAKE(p, x+1, y) +
                            FAKE(p, x-1, y+1) +
                            FAKE(p, x, y+1) +
                            FAKE(p, x+1, y+1);

                /* Apply Conway's rules...
                   (yes, I know this is clever code!)
                */
                FAKE(q, x, y) = ((live == 3) ||
                         ((live == 2) &&
                          FAKE(p, x, y)));
            }
        }

        /* Swap our notion of p and q...
           this saves us copying every timestep
        */
        {
            register unsigned char *pt = p;
            p = q;
            q = pt;
        }
    } /* End iterate timestep for block */

    /* Done; write-out results */
    write_P1(masterx, mastery, q);
    exit(0);
}

以下应将大数组masterP分解为 4x4“块”:

int loopx , loopy;
int cnt = 0;
for(loopy = 0; loopy < divisions; ++loopy){
    for(loopx = 0; loopx < divisions; ++loopx){
        x=1;
        //Fill p
        for (j=(loopy*ydim)+1; j<((loopy+1)*ydim+2); ++j){
            for( i=(loopx*xdim)+1; i<((loopx+1)*xdim+2); ++i){
                //printf("j: %d i: %d\n",j,i);
                p[x]=masterP[i+(loopy*j)+1];
                printf("%d",p[x]);
                x++;
            }
        }
        //Print P contents
        printf("\nIteration Y:%d X:%d\n",loopy, loopx);
        write_P1(xdim, ydim, p);

    }
}

但是,我得到的数组都是0。说起来不妥当吗

  p[x]=masterP[i+(loopy*j)+1];

Arrayp是一个创建为 4x4 “块”的数组masterP

样本输出:

P1  
# CREATOR: GIMP PNM Filter Version 1.1
32 32
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000001000000000000
00000000000001100000000000000000
00001100000000100011100000000000
00001100000000000000000000000000
00000011000000000000000000000000
00000011000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000011100000
01000101001000000000000000000000
01000101010000011100000000000000
01000101100000111000000000000000
01000101010000000000000000000000
01000101001000000000000000000000
00111001001000000000000001000000
00000000000000000000000001000000
00000000000000000000000001000000
00000000000000000000000000000000
00000000010000000000000000000000
00000000001000000000000000000000
00000000111000000000000000000000
00000000000000000000000110000000
00000000000000000000001001000000
00110000000000000000000110000000
01100000000000000110000000001000
001000000000000001100000000000001100
00000000000000011000000000000100
00000000000000000000000000000000
Check master P
P1
# CREATOR: P1IO
32 32
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000001000000000000
00000000000001100000000000000000
00001100000000100011100000000000
00001100000000000000000000000000
00000011000000000000000000000000
00000011000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000011100000
01000101001000000000000000000000
01000101010000011100000000000000
01000101100000111000000000000000
01000101010000000000000000000000
01000101001000000000000000000000
00111001001000000000000001000000
00000000000000000000000001000000
00000000000000000000000001000000
00000000000000000000000000000000
00000000010000000000000000000000
00000000001000000000000000000000
00000000111000000000000000000000
00000000000000000000000110000000
00000000000000000000001001000000
00110000000000000000000110000000
01100000000000000110000000001000
00100000000000000110000000001100
00000000000000011000000000001100
00000000000000011000000000000100
00000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:0 X:0
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:0 X:1
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:0 X:2
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:0 X:3
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:1 X:0
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:1 X:1
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:1 X:2
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:1 X:3
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:2 X:0
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:2 X:1
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:2 X:2
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:2 X:3
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:3 X:0
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:3 X:1
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:3 X:2
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000
Iteration Y:3 X:3
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000

P1
# CREATOR: P1IO
32 32
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000100000
11011100011111100111110000000000
11110001111110011111000111111000
00000000000101111100000000000111
00000000000000000010000000110111
01111110010000000100000001111110
00000100000000100000001101110000
00000000000000000000000000000000
00000000000000000001111100011111
01111100011111000111110001111100
11110000111100011111000111110001
11000111111001111100011111100111
00011111100111110001111110011111
01111110011111000111111001111100
11111001111100011111100111110001
11100111110001111110011111000111
10011111000111111001111100011111
01111100000000000111110001111110
11110001111110000000000000000100
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000

感谢您的帮助!

4

3 回答 3

3

您可以使用 MPI 派生的数据类型以更优雅的方式做到这一点。看看MPI_Type_vector。它创建一个派生数据类型,指示 MPI 获取旧数据类型count的元素块,blocklength每个元素块由stride元素分隔:

block 1      block 2      block 3 ..... block count
   |            |            |             |
   V            V            V             V
+-----+------+-----+------+-----+-------+-----+------
|XXXXX|      |XXXXX|      |XXXXX|       |XXXXX|
+-----+------+-----+------+-----+-------+-----+------
|<- stride ->|            |     |
                        ->|-----|<-
                        blocklength

现在,如果您设置count为 4、4blocklengthstride一行的长度,那么这正是从大数组中取出 4x4 块的数据类型。您可以在发送和接收操作中使用此数据类型,并使用一些 MPI 类型的按摩魔法(特别是使用 调整类型的大小MPI_Type_create_resized),您甚至可以在分散/收集操作中使用它。

例如,要在第二个 4 行上发送第二个块,假设每行有row4cols4 列:

MPI_Datatype block4type;

MPI_Type_vector(4, 4, 4*rows4cols, MPI_UNSIGNED_CHAR, &block4type);
MPI_Type_commit(&block4type);

MPI_Send(&masterP[(2-1)*(4*4*rows4cols) + (2-1)*4], 1, block4type,
         dest_rank, 0, MPI_COMM_WORLD);

这将发送一条包含 16 个类型元素的消息MPI_UNSIGNED_CHAR。接收器可以简单地将其接收到一个 4x4 数组中:

unsigned char block[4][4];
MPI_Status status;

MPI_Recv(block, 4*4, MPI_UNSIGNED_CHAR,
         master_rank, 0, MPI_COMM_WORLD, &status);

这也适用于另一个方向——worker 发送 16 个元素,MPI_UNSIGNED_CHARmaster 用于block4type接收 4x4 块中适当位置的数据masterP

于 2013-02-11T13:14:41.630 回答
2

你永远不会增加x. 看起来你打算这样做。因此,您总是将数据分配给p[1]. 看起来p[x]你真的应该分配给,而不是分配给p[cnt]

于 2013-02-11T02:41:55.110 回答
1

感谢大家的支持!当然帮助我朝着正确的方向前进。我终于整理了一些源自我的索引的问题。

对于 32x32 图像,一维数组应该有 1024 个元素,但是我们的处理函数在 32x32 图像的 4x4 块周围设置了一个“假区域”或缓冲区。对于假区域,尺寸为 (x+2)x(y+2),因此对于 32x32 图像,我应该期望 1d 数组中有 1156 个元素。以前我没有正确处理假区域添加的环绕和额外缓冲区空间。

我使用 4 个 for 循环遍历较大的 32x32 图像以生成 16 个 8x8 图像块。我相信使用 2d 矩阵会更容易,但是我们的处理函数设置为接受 1d 数组。与为 1d 操作导出正确的索引模式相比,将处理函数转换为接受 2d 数组会产生更多开销。下面提供了使用的 4 个 for 循环:

    int loopx , loopy, pe_num;
int cnt = 0;

for(loopy = 0; loopy < divisions; loopy++){
    for(loopx = 0; loopx < divisions; loopx++){
        //Fill p
        cnt=(xdim+3); //Reinitialize the first index for every new p to xdim+2
        for (j=0; j<(ydim); j++){
            for( i=0; (i<xdim); i++){
                p[cnt]=masterP[((masterx+2)+(j*(masterx+2))+(loopy*(masterx+2)*ydim)+(loopx*xdim)+i+1)];
                //printf("%d",masterP[((masterx+2)+(j*(masterx+2))+(loopy*(masterx+2)*ydim)+(loopx*xdim)+i)]);  
                if( ((cnt+1)%(xdim+2))==0) //skip over fake zone
                    cnt = cnt+3;
                else
                    cnt++;
            }
        }
        pe_num = ((loopy*divisions)+loopx);
        //Print "chunk" p contents
        printf("\nPE #%d\n",pe_num);
        write_P1(xdim, ydim, p);
        //MPI_Send(p, sizeof(p), MPI_UNSIGNED_CHAR, pe_num, 0, MPI_COMM_WORLD);
    }
} 

对于输入:

P1
# CREATOR: GIMP PNM Filter Version 1.1
32 32
01111111111110000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000001000000000000
00000000000001100000000000000000
00001100000000100011100000000000
00001100000000000000000000000000
00000011000000000000000000000000
00000011000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000011100000
01000101001000000000000000000000
01000101010000011100000000000000
01000101100000111000000000000000
01000101010000000000000000000000
01000101001000000000000000000000
00111001001000000000000001000000
00000000000000000000000001000000
00000000000000000000000001000000
00000000000000000000000000000000
00000000010000000000000000000000
00000000001000000000000000000000
00000000111000000000000000000000
00000000000000000000000110000000
00000000000000000000001001000000
00110000000000000000000110000000
01100000000000000110000000001000
00100000000000000110000000001100
00000000000000011000000000001100
00000000000000011000000000000100
00000000000000000000000000000000

我成功地分成了 16 个块,形成了原始图像的 4x4 网格:

Check master P
P1
# CREATOR: P1IO
32 32
01111111111110000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000001000000000000
00000000000001100000000000000000
00001100000000100011100000000000
00001100000000000000000000000000
00000011000000000000000000000000
00000011000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000011100000
01000101001000000000000000000000
01000101010000011100000000000000
01000101100000111000000000000000
01000101010000000000000000000000
01000101001000000000000000000000
00111001001000000000000001000000
00000000000000000000000001000000
00000000000000000000000001000000
00000000000000000000000000000000
00000000010000000000000000000000
00000000001000000000000000000000
00000000111000000000000000000000
00000000000000000000000110000000
00000000000000000000001001000000
00110000000000000000000110000000
01100000000000000110000000001000
00100000000000000110000000001100
00000000000000011000000000001100
00000000000000011000000000000100
00000000000000000000000000000000


PE #0
P1
# CREATOR: P1IO
8 8
01111111
00000000
00000000
00000000
00000000
00001100
00001100
00000011


PE #1
P1
# CREATOR: P1IO
8 8
11111000
00000000
00000000
00000000
00000110
00000010
00000000
00000000


PE #2
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00010000
00000000
00111000
00000000
00000000


PE #3
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000


PE #4
P1
# CREATOR: P1IO
8 8
00000011
00000000
00000000
00000000
01000101
01000101
01000101
01000101


PE #5
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00100000
01000001
00000011
01000000


PE #6
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
01000000
00000000
00000000


PE #7
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
01100000
00000000
00000000
00000000
00000000


PE #8
P1
# CREATOR: P1IO
8 8
01000101
00111001
00000000
00000000
00000000
00000000
00000000
00000000


PE #9
P1
# CREATOR: P1IO
8 8
00100000
00100000
00000000
00000000
00000000
01000000
00100000
01100000


PE #10
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000


PE #11
P1
# CREATOR: P1IO
8 8
00000000
01000000
01000000
01000000
00000000
00000000
00000000
00000000


PE #12
P1
# CREATOR: P1IO
8 8
00000000
00000000
00110000
01100000
00100000
00000000
00000000
00000000


PE #13
P1
# CREATOR: P1IO
8 8
00000000
00000000
00000000
00000000
00000000
00000001
00000001
00000000


PE #14
P1
# CREATOR: P1IO
8 8
00000001
00000010
00000001
01100000
01100000
00000000
00000000
00000000


PE #15
P1
# CREATOR: P1IO
8 8
10000000
01000000
00000000
00001000
00001100
00001100
00000100
00000000

再次感谢那些做出贡献的人。Hristo,我很有兴趣尝试您提出的建议,我相信这是一种更有效的方法!

于 2013-02-12T02:13:02.693 回答