【问题标题】:Sending array of structs in MPI在 MPI 中发送结构数组
【发布时间】:2021-06-11 19:15:49
【问题描述】:

我有一个如下所示的数据结构

struct test{
  double a1;
  double a2;
}

并有一个指针test *info = nullptr; 指向结构数组的开头。

问题是如何在不将其转换为两个单独的向量的情况下广播此数组。

  1. 我尝试创建 mpi_type_struct 没有成功。
  2. 我试图打包我的结构数据没有工作。 到目前为止,我看到的案例仅对一个结构有效,但对结构数组无效。

这是我迄今为止尝试过的

  int block[2] = {1,1};
  MPI_Aint displacements[2];
  MPI_Aint baseaddr, addr1, addr2;
  MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
  MPI_Datatype contigs[6];
  if(my_rank==0){
    for (int i = 0; i < 6; i++)
    {
      MPI_Get_address ( &info[i], &baseaddr);
      MPI_Get_address ( &info[i].num_edges, &addr1);
      MPI_Get_address ( &info[i].num_vertices, &addr2);
      displs[0] = addr1 - baseaddr;
      displs[1] = addr2 - baseaddr;

      MPI_Type_create_struct(2, block, displacements, types, &contigs[i]);
      MPI_Type_commit(&contigs[i]);
    }
  MPI_Bcast(info, 6, *contigs, 0, comm);

【问题讨论】:

    标签: c performance parallel-processing mpi hpc


    【解决方案1】:
      int block[2] = {1,1};
      MPI_Aint displacements[2];
      MPI_Aint baseaddr, addr1, addr2;
      MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
      MPI_Datatype contigs[6];
      if(my_rank==0){
        for (int i = 0; i < 6; i++)
        {
          MPI_Get_address ( &info[i], &baseaddr);
          MPI_Get_address ( &info[i].num_edges, &addr1);
          MPI_Get_address ( &info[i].num_vertices, &addr2);
          displs[0] = addr1 - baseaddr;
          displs[1] = addr2 - baseaddr;
    
          MPI_Type_create_struct(2, block, displacements, types, &contigs[i]);
          MPI_Type_commit(&contigs[i]);
        }
    

    您不必构建数组中的每个struct。您可以改为MPI_Type_create_struct 其中之一,然后使用MPI_Bcast

    一个完整的例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    void defineStruct(MPI_Datatype *tstype);
    
    typedef struct S{
      double a1;
      double a2;
    } S;
    
    void defineStruct(MPI_Datatype *tstype) {
        const int count = 2;
        int          blocklens[count] = {1,1};
        MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
        MPI_Aint     disps[count] = {offsetof(S,a1), offsetof(S,a2)};
    
        MPI_Type_create_struct(count, blocklens, disps, types, tstype);
        MPI_Type_commit(tstype);
    }
    
    int main(int argc,char *argv[]){
        MPI_Init(NULL,NULL);
        int world_rank; 
        MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
        MPI_Datatype structtype;
        int total_size = 5;
        S *info = malloc(sizeof(S) * total_size);
        
        // Just adding some fake values
        if(world_rank == 0){   
            for(int i = 0; i < total_size; i++){
               info[i].a1 = i * i;
               info[i].a2 = i * (i+1);
            }
        }    
    
        defineStruct(&structtype);
        MPI_Bcast(info, total_size, structtype, 0, MPI_COMM_WORLD);  
              
        if(world_rank != 0){
          for(int i = 0; i < total_size; i++){
             printf("%lf %lf\n", info[i].a1, info[i].a2);
          }
        }
        free(info);
        MPI_Finalize();
        return 0;
     }
    

    输出:

    0.000000 0.000000
    1.000000 2.000000
    4.000000 6.000000
    9.000000 12.000000
    16.000000 20.000000
    

    【讨论】:

      【解决方案2】:

      MPI_TYPE_STRUCT 不适用于描述 C 结构数据类型(尽管您可以使用它——您可以使用 MPI_TYPE_STRUCT 做任何事情)。它用于描述由多个数据类型组成的数据类型。

      'double' 相当安全,但为了处理成员填充,我认为获取每个项目的地址是正确的调用。

      @dreamcrash 的解决方案创建单一数据类型并发送该类型的“计数”。另一种方法是用 MPI_TYPE_HINDEXED_BLOCK 来描述内存(因为块大小总是 sizeof(double)。

      【讨论】:

      • 嗨 Rob,“offsetof”已经解决了填充问题
      猜你喜欢
      • 2013-12-12
      • 2016-09-18
      • 2014-12-20
      • 2021-07-23
      • 2015-11-19
      • 2018-11-09
      • 2015-08-20
      • 1970-01-01
      • 2012-03-19
      相关资源
      最近更新 更多