1

Open MPIを使用して、PGMファイルの2Dアレイを10台の稼働中のコンピューターに配布する必要があります。次に、配列の各値を操作してネガティブイメージ(255-i)を取得し、出力を出力し直す必要があります。mpi_scatterデータの使用とmpi_gather配布を考えています。ここでの問題は、2次元配列をサブ配列に読み込み、動作中の各コンピューターにサブ配列を送信して操作を行う方法です。私はこのプログラムをCで書いています。

誰かが私がこの問題を解決するのを手伝ったり、アイデアを与えることができますか?ありがとうございました。

以下は、PGMファイルの配列の例です。

P2
#作成者'xvballoons_bw.tif'
640 480
255
232227220216212209207206205205​​205​​207208209210211212
211 211 213 212 211 210 209 210 210 211 212 211 210 210 210 210 211
210210210210209210209208209208209210209208210209209
208208208209208208208207207207206207207207207207207207
207207207207205204206205205​​204204204203202203202201
201201200199199200199198198198197197198191197196195195
194193192192191191190190190190189189190188188188188187
187187186186186186187186186187188188187186186186185
186186186187186186186185185187186185186185185186185
184185186185186186186185186185185185184183184184183
4

2 に答える 2

1

PGMファイルを読み取る最も簡単な方法は、netpbmパッケージのlibpgmを使用することです。

以下を使用してpgmファイルを読み取ります。

gray **image;
FILE *fp;
int cols; # num columns
int rows; # num rows
int maxval; # max grayscale value

fp = fopen("input.pgm","r");
image = pgm_readpgm( fp, &cols, &rows, &maxval); 

行/列をループすることでネガティブイメージを取得できるようになりました。

for (i = 0; i < rows; i++)
    for (j = 0; j < cols; j++)
        image[i][j] = maxval - image[i][j];

トリッキーな点はimage、メモリ内で連続していない可能性があるため、MPIノード全体にタスクを分散することです(私はチェックしていません)。コードを掘り下げてストレージパターンを決定し、それに応じて配列を分散/収集することもできますが、将来(可能性は低いですが)変更されてコードが破損しないという保証はありません。

これを行うための可能なが最適ではない方法は、メモリ内で隣接する一時バッファを作成し、それを分散して、後でイメージを再構築することです。例えば

gray *buffer = malloc(sizeof(gray) * rows * cols);
for (i = 0; i < rows; i++)
    for (j = 0; j < cols; j++)
        buffer[(i*cols)+j] = image[i][j];

これで、準備が整いました

  1. ノード間でバッファを分散させる
  2. maxval各ノードにブロードキャストする必要がある場合があります。
  3. 各ノードのパフォーマンスbuffer[n] = maxval - buffer[n];
  4. バッファをマスターに戻します
  5. 出力画像を再構成します

データに書き戻すことで画像を再構築できます。形式にimage精通している場合は、pgmファイルを手動で印刷することもできます。

MPI操作に使用するデータ型については、のtypedefであるMPI_UNSIGNEDため、機能します。ただし、厳密に上位互換性を保つために、を使用して乗算することができます。grayunsigned intMPI_BYTEsend_countsizeof(gray)

libpgmを使用しない

ファイルを手動で読み込みたい場合は、PGMファイルが(P2ではなくP5)プレーン形式であるため、それほど難しくはありません。

フォーマットが有効であると仮定すると、次のことを行う必要があります。

  1. ファイルを開く
  2. 最初の2行をスキップします
  3. 列と行を読みます:fscanf(fp,"%d %d", &cols, &rows);
  4. maxvalで読む:fscanf(fp,"%d", &maxval);
  5. colsおよびに従ってバッファを割り当てますrows
  6. 列/行をループして繰り返し、残りの画像を読み込みますfscanf(fp,"%d", &buffer[r][c]);
于 2011-02-22T12:25:16.687 に答える
0

私は通常、既存のライブラリを使用してファイルを読み取ることについてShawnChinに同意します。この場合、ファイル形式が非常に単純であり、MPIがデータがメモリにどのように配置されているかを知ることが非常に重要であるため、私は同意しない可能性があります。nxmの連続する1次元配列として割り当てられた2次元のnxm配列は、メモリ全体に散在する行とは大きく異なります。いつものように、これは実際のマルチd配列を持たないことに対するCのせいです。一方、libnetpbmライブラリをチェックして、それがどのように割り当てられているかを確認するか、Shawnが示唆しているように、読み込んだ後にすべてを連続したメモリにコピーすることができます。

また、これは(バイナリ)P5形式の方が実際には簡単であることに注意してください。これは、1つのプロセッサですべての読み取りを実行し、スキャッタ/ギャザーを使用するのではなく、MPI-IOを使用してデータを最初から並列に読み取ることができるためです。データ配布を行います。ASCIIファイルでは、レコードの長さが実際にはわからないため、調整されたI/Oが非常に困難になります。

また、これは実際には2次元の問題ではないことに注意してください。つまり、配列のすべての部分に対して要素ごとの操作を実行しているだけです。したがって、データを1次元配列として扱い、ジオメトリを無視するだけで、作業を大幅に簡素化できます。これ、(たとえば)画像に2Dフィルターを適用する場合には当てはまりません。ジオメトリが重要であり、それに応じてデータを分割する必要があるためです。しかし、ここでは気にしません。

最後に、この単純なケースでも、画像内のセルの数がMPIタスクの数で均等に分割されない可能性があるため、scattervとgathervを使用する必要があります。配列をパディングして均等に分割するだけで、ここでロジックを単純化できます。次に、ここで余分な手順のいくつかを回避できます。

したがって、があり、ポインタを単一の連続したメモリブロックに返すことがわかっている場合はread_pgm()write_pgm()次のように実行できます。

int main(int argc, char **argv) {
    int ierr;
    int rank, size;
    int **greys;
    int rows, cols, maxval;
    int ncells;
    int mystart, myend, myncells;
    const int IONODE=0;
    int *disps, *counts, *mydata;
    int *data;

    ierr = MPI_Init(&argc, &argv);
    if (argc != 3) {
        fprintf(stderr,"Usage: %s infile outfile\n",argv[0]);
        fprintf(stderr,"       outputs the negative of the input file.\n");
        return -1;
    }            

    ierr  = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    ierr |= MPI_Comm_size(MPI_COMM_WORLD, &size);
    if (ierr) {
        fprintf(stderr,"Catastrophic MPI problem; exiting\n");
        MPI_Abort(MPI_COMM_WORLD,1);
    }

    if (rank == IONODE) {
        if (read_pgm(argv[1], &greys, &rows, &cols, &maxval)) {
            fprintf(stderr,"Could not read file; exiting\n");
            MPI_Abort(MPI_COMM_WORLD,2);
        }
        ncells = rows*cols;
        disps = (int *)malloc(size * sizeof(int));
        counts= (int *)malloc(size * sizeof(int));
        data = &(greys[0][0]); /* we know all the data is contiguous */
    }

    /* everyone calculate their number of cells */
    ierr = MPI_Bcast(&ncells, 1, MPI_INT, IONODE, MPI_COMM_WORLD);
    myncells = ncells/size;
    mystart = rank*myncells;
    myend   = mystart + myncells - 1;
    if (rank == size-1) myend = ncells-1;
    myncells = (myend-mystart)+1;
    mydata = (int *)malloc(myncells * sizeof(int));

    /* assemble the list of counts.  Might not be equal if don't divide evenly. */
    ierr = MPI_Gather(&myncells, 1, MPI_INT, counts, 1, MPI_INT, IONODE, MPI_COMM_WORLD);
    if (rank == IONODE) {
        disps[0] = 0;
        for (int i=1; i<size; i++) {
            disps[i] = disps[i-1] + counts[i-1];
        }
    }

    /* scatter the data */
    ierr = MPI_Scatterv(data, counts, disps, MPI_INT, mydata, myncells, 
                        MPI_INT, IONODE, MPI_COMM_WORLD);

    /* everyone has to know maxval */
    ierr = MPI_Bcast(&maxval, 1, MPI_INT, IONODE, MPI_COMM_WORLD);

    for (int i=0; i<myncells; i++)
        mydata[i] = maxval-mydata[i];

    /* Gather the data */
    ierr = MPI_Gatherv(mydata, myncells, MPI_INT, data, counts, disps, 
                        MPI_INT, IONODE, MPI_COMM_WORLD);

    if (rank == IONODE) {
        write_pgm(argv[2], greys, rows, cols, maxval);
    }

    free(mydata);
    if (rank == IONODE) {
        free(counts);
        free(disps);
        free(&(greys[0][0]));
        free(greys);
    }
    MPI_Finalize();
    return 0;
}
于 2011-02-24T14:33:20.220 に答える