2016-12-19 13 views
0

概要:私はMPI_Type_create_struct()を使用して作成したデータ型が正しいことをテストしているため、正しい値が送信されます。私は配列に格納されている値を他のプロセッサに転送することに問題があります。私はこれがデータ型mpiboundを作成するために使用された配列のインデックス[]に格納されているオフセットと各構造体バインドの配列のメモリアドレスに問題があると考えます。MPI_Type_create_struct()を使用してC言語の動的配列を含む構造体を転送する

問題:私はMPIを使用しているプログラムに取り組んでいます。最終目標は、MPI_Gatherv()を使用して、以下に宣言されているboundという構造体の配列から値を収集することです。

struct bound { 
    int  n; 
    char* name; 
    double* lat; 
    double* lon; 
}; 

私はMPI_Type_create_struct()を正しく使用していることを確認するためのテストプログラムを作成しました。 MPI_Type_create_struct()を呼び出す関数を以下に記述します。

void CreateBoundType (struct bound a_bound) { 
    int blocklens[4];    /*Block Lengths of data in structure*/ 
    MPI_Datatype old_types[4];  /*Data types of data in structure*/ 
    MPI_Aint indices[4];   /*Byte displacement of each piece of data*/ 
    MPI_Aint addr1, addr2, addr3, addr4, baseaddr; 

    /*Set block lengths*/ 
    blocklens[0] = 1; 
    blocklens[1] = 10; 
    blocklens[2] = NPT_MAX; 
    blocklens[3] = NPT_MAX; 

    /*Set Data Types*/ 
    old_types[0] = MPI_INT; 
    old_types[1] = MPI_CHAR; 
    old_types[2] = MPI_DOUBLE; 
    old_types[3] = MPI_DOUBLE; 

    /*Set byte displacement for each piece of data in structure*/ 
    /*!!!!!I expect that the following 8 lines cause my problem!!!!!!*/ 
    MPI_Get_address (&a_bound,   &baseaddr); 
    MPI_Get_address (&a_bound.num_pts, &addr1); 
    MPI_Get_address (a_bound.label, &addr2); 
    MPI_Get_address (a_bound.lat,  &addr3); 
    MPI_Get_address (a_bound.lon,  &addr4); 
    indices[0] = addr1 - baseaddr; 
    indices[1] = addr2 - baseaddr; 
    indices[2] = addr3 - baseaddr; 
    indices[3] = addr4 - baseaddr; 

    /*Create structure type in MPI so that we can transfer boundaries between nodes*/ 
    MPI_Type_create_struct(4,blocklens,indices,old_types,&mpibound); 
    MPI_Type_commit(&mpibound); 
    return; 
} 

私が使用するバッファ構造体の一部であるMPI_Bcast()アレイに記憶された値への呼び出しで、(グローバル変数、mpiboundある)私が作成したデータ型を使用しようとしますは更新されませんが、整数値n(nは配列の長さ)はすべてのプロセッサで変更されます。したがって、私の問題は、mpiboundを定義するために使用されるオフセット(インデックス[4])と関係していると思います。

以下、この関数をどのように呼び出して構造体を設定するかを示す主関数を書きました。 (私は私ができる限り短く、それを維持するためにMPI_Initおよび他のそのような関数への呼び出しを省いている)MPi_Bcastを呼び出した後、いくつかのprint文を置く

int main (int argc, char **argv) { 

    /*Initialise MPI etc*/... 

    /*Create structure to broadcast*/ 
    struct bound my_bound; 
    my_bound.name = strdup(string); 
    my_bound.lat = malloc(NPT_MAX*sizeof(double)); 
    my_bound.lon = malloc(NPT_MAX*sizeof(double)); 
    if(rank == 0) { 
     my_bound.n  = 5; 
     my_bound.lat[0] = 2.6; 
     my_bound.lon[0] = 4.2; 
    } 

    /*Call the function that creates the type mpibound*/ 
    CreateBoundType(my_bound); 

    /*Create buffer to be used in a Broadcast from the root processor (rank 0)*/ 
    struct bound *buff = malloc(sizeof(struct bound)); 
    buff->lat = malloc(NPT_MAX*sizeof(double)); 
    buff->lon = malloc(NPT_MAX*sizeof(double)); 
    buff = &my_bound; 

    /*Cast values in buffer from proc 0 to all others*/ 
    MPI_Bcast(buff,1,mpibound,0,MPI_COMM_WORLD); 

    /*Print values and checks, free memory etc*/... 

    return(EXIT_SUCCESS); 
} 

は示していランク> 0の値を持つprocsの上nはランク0からのブロードキャストに更新されますが、latとlonの配列の最初の要素はまだ0です。

私が大いに助けてくれれば幸いです。私はこれをできる限り短く保つように努めましたが、これは私が作成できる最高のバージョンです。

読んでいただきありがとうございます!

+1

あなたのコードはほとんど意味がありません。あなたは2つの構造体と両方の配列のためのいくつかのメモリを割り当てますが、 'buff =&my_bound'を実行することで2番目の構造体のメモリを完全に捨てることができます。とにかく、適切な[mcve]とより具体的な予想と実際の出力を準備してください。 – Zulan

+1

私は彼のコメントに@Zulanを返す。あなたのコードは間違いでいっぱいです。私はMPIの問題以上のものだと思っています。あなたがここで欠けているのはCの基本的な理解です。いったんC言語の基本が安定すれば、MPIに取り組もうとすることでレベルアップすることができますが、MPI + CでプログラミングするにはC言語が必須です。 – Gilles

答えて

1

Zulanが指摘したように、コードには意味をなさないものがいくつかあります。しかし、主な問題は、あなたがMPIデータ型mpiboundを値コピーのメモリアドレスから構成されていることを意味値によって構造を渡している

void CreateBoundType (struct bound a_bound) { 
//     HERE HERE HERE HERE 

に位置しています。コピーにはlabellat、およびlonの同じポインタ値が含まれていますが、ベースは別の場所に配置されます。したがって、そのデータ型を使用して、mainの構造体インスタンスを送信することはできません。オフセットは有効ではありません。

代わりに行うべきことは、アドレスで構造体を渡すことです。変更は最小限である:あなたが操作を収集しながら、(v)のオフセットなどの構造体は、単一のインスタンスでのみ有効です収集するために、あなたの最終目標を達成することができません

void CreateBoundType (struct bound *a_bound) { 
    ... 
    MPI_Get_address(a_bound,   &baseaddr); 
    MPI_Get_address(&a_bound->n, &addr1); 
    MPI_Get_address(a_bound->label, &addr2); 
    MPI_Get_address(a_bound->lat,  &addr3); 
    MPI_Get_address(a_bound->lon,  &addr4); 
    ... 
} 

... 
/*Call the function that creates the type mpibound*/ 
CreateBoundType(&my_bound); 
... 

注配列を作成します。配列の各要素は異なるオフセットを持つ可能性が高いため、別々のMPIデータ型が必要になります。

latlonのメモリをすべて割り当てているので、単純に構造体に配列を使用しないのはなぜですか?

struct bound { 
    int  n; 
    char name[10]; 
    double lat[NPT_MAX]; 
    double lon[NPT_MAX]; 
}; 

MPI_Type_create_resizedを使用してsizeof(struct bound)にその作成した後、MPI構造データ型のサイズを変更することを忘れないでください。

また、構造体へのポインタは最初の要素へのポインタであるため、nのオフセットを明示的に計算する必要はありません。言語によって0になることが保証されています。

関連する問題