3

MPI_Gather で送信しようとしている次のデータ構造があります。

struct set {
    int nbits;
    char  bits[];
};

問題は、上記の構造のすべてのアイテムを収集できず、最初のアイテムのみを収集できないことです。残りの項目は意味がありません。

テストケースは次のとおりです。

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

#include "mpi.h"

#define SIZE 10

struct set {
    int nbits;
    char bits[];
};

int main(int argc, char *argv[]) {
    int np, rank, i;
    struct set *subsets, *single;
    void *buf;

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

    single = malloc(sizeof(struct set) + SIZE);

    if(rank == 0) {
            subsets = malloc((sizeof(struct set) + SIZE) * np);
    }

    buf = &subsets[0];

    MPI_Datatype set_type, oldtypes[2];
    int blockcounts[2];
    MPI_Aint offsets[2];
    MPI_Aint addr[3];

    MPI_Get_address(single, &addr[0]);
    MPI_Get_address(&single->nbits, &addr[1]);
    MPI_Get_address(&single->bits, &addr[2]);

    offsets[0] = addr[1] - addr[0];
    oldtypes[0] = MPI_INT;
    blockcounts[0] = 1;

    offsets[1] = addr[2] - addr[0];
    oldtypes[1] = MPI_CHAR;
    blockcounts[1] = SIZE;

    MPI_Type_create_struct(2, blockcounts, offsets, oldtypes, &set_type);
    MPI_Type_commit(&set_type);

    single->nbits = 2;

    for(i=0; i<single->nbits; i++)
            single->bits[i] = 'A' + rank;

    MPI_Gather(single, 1, set_type, buf, 1, set_type, 0, MPI_COMM_WORLD);

    if(rank == 0) {
            void *ptr;
            struct set *fs;
            int size;

            MPI_Type_size(set_type, &size);

            ptr = buf;

            for(i=0; i<np; i++) {
                    size_t j;

                    fs = ptr;
                    printf("from rank %d: bits => %p nbits => %d\n", i, fs->bits, fs->nbits);

                    for(j=0; j<2; j++)
                            printf("from rank %d: buf[%d] = %#x\n",
                                    i, j, fs->bits[j]);
                    ptr += size;
            }
    }

    MPI_Type_free(&set_type);

    MPI_Finalize();
}

どんな助けでも大歓迎です。

4

1 に答える 1

0

MPI問題は、構造体や MPI 型を使用したポインター演算ほどではありません。

あなたが持っている

        void *ptr;
        struct set *fs;
        int size;

        MPI_Type_size(set_type, &size);

        ptr = buf;

        for(i=0; i<np; i++) {
                size_t j;

                fs = ptr;
                printf("from rank %d: bits => %p nbits => %d\n", i, fs->bits, fs->nbits);

                for(j=0; j<2; j++)
                        printf("from rank %d: buf[%d] = %#x\n",
                                i, j, fs->bits[j]);
                ptr += size;
        }
}

しかし、MPI_Type_size実際には型のデータ量を示します。パディングがある場合 (文字配列を単語境界に配置するためにおそらくここにあるでしょう)、これは と同じではありませんsizeof。ここで MPI 関数を使用したい場合、その 1 つの関数呼び出しを に切り替えるとMPI_Type_extent、実際には型がまたがる範囲全体が表示され、コードが実行されます... しかし、まだ問題があります。

と の違いをsizeof(struct set)+SIZE見るMPI_Type_extent()と、同じではないことがわかります。これ:

#define SIZE 10
struct set {
  int nbits
  char nbits[]
}

...

malloc(sizeof(struct set)+SIZE);

と同じではありません

struct set {
  int nbits
  char nbits[SIZE]
}

malloc(sizeof(struct set));

これは、 のサイズsubsetsが間違っていて、 を呼び出したときにメモリ エラーが発生したことを意味しますMPI_Gather

いくつかの異なる方法でこれを回避できますが、最も簡単な (そして行数の点で最も短い) 方法は、既にサイズが設定されている配列で構造体を定義し、ポインター演算の代わりに配列インデックスを使用することです。

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

#include "mpi.h"

#define SIZE 10

struct set {
    int nbits;
    char bits[SIZE];
};

int main(int argc, char *argv[]) {
    int np, rank, i;
    struct set *subsets, *single;

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

    single = malloc(sizeof(struct set));

    if(rank == 0) {
            subsets = malloc(sizeof(struct set) * np);
    }

    MPI_Datatype set_type, oldtypes[2];
    int blockcounts[2];
    MPI_Aint offsets[2];
    MPI_Aint addr[3];

    MPI_Get_address(single, &addr[0]);
    MPI_Get_address(&single->nbits, &addr[1]);
    MPI_Get_address(&single->bits, &addr[2]);

    offsets[0] = addr[1] - addr[0];
    oldtypes[0] = MPI_INT;
    blockcounts[0] = 1;

    offsets[1] = addr[2] - addr[0];
    oldtypes[1] = MPI_CHAR;
    blockcounts[1] = SIZE;

    MPI_Type_create_struct(2, blockcounts, offsets, oldtypes, &set_type);
    MPI_Type_commit(&set_type);

    single->nbits = 2;

    for(i=0; i<single->nbits; i++)
            single->bits[i] = 'A' + rank;

    MPI_Gather(single, 1, set_type, &(subsets[0]), 1, set_type, 0, MPI_COMM_WORLD);

    if(rank == 0) {
            for(i=0; i<np; i++) {
                    struct set *fs = &(subsets[i]);
                    printf("from rank %d: bits => %p nbits => %d\n", i, fs->bits, fs->nbits);

                    for(int j=0; j<2; j++)
                            printf("from rank %d: buf[%d] = %#x\n",
                                    i, j, fs->bits[j]);
            }
    }

    MPI_Type_free(&set_type);

    MPI_Finalize();
}

追加するために更新されました。それができない場合は、バッファ割り当てのサイズを変更して、データを次の場所に収集します。

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

#define SIZE 10

struct set {
    int nbits;
    char bits[];
};

int main(int argc, char *argv[]) {
    int np, rank, i;
    struct set *single;
    void *buf;
    ptrdiff_t extent;

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

    single = malloc(sizeof(struct set) + SIZE);

    MPI_Datatype set_type, oldtypes[2];
    int blockcounts[2];
    MPI_Aint offsets[2];
    MPI_Aint addr[3];

    MPI_Get_address(single, &addr[0]);
    MPI_Get_address(&single->nbits, &addr[1]);
    MPI_Get_address(&single->bits, &addr[2]);

    offsets[0] = addr[1] - addr[0];
    oldtypes[0] = MPI_INT;
    blockcounts[0] = 1;

    offsets[1] = addr[2] - addr[0];
    oldtypes[1] = MPI_CHAR;
    blockcounts[1] = SIZE;

    MPI_Type_create_struct(2, blockcounts, offsets, oldtypes, &set_type);
    MPI_Type_commit(&set_type);

    MPI_Type_extent(set_type, &extent);
    buf = malloc((int)extent * np);

    single->nbits = 2;

    for(i=0; i<single->nbits; i++)
            single->bits[i] = 'A' + rank;

    MPI_Gather(single, 1, set_type, buf, 1, set_type, 0, MPI_COMM_WORLD);

    if(rank == 0) {
            struct set *fs = buf;
            for(i=0; i<np; i++) {
                    printf("from rank %d: bits => %p nbits => %d\n", i, fs->bits, fs->nbits);

                    for(int j=0; j<2; j++)
                            printf("from rank %d: buf[%d] = %#x\n",
                                    i, j, fs->bits[j]);

                    fs = (struct set *)((char *)fs + extent);
            }
    }

    MPI_Type_free(&set_type);

    MPI_Finalize();
}
于 2013-02-03T17:33:03.960 に答える