【问题标题】:using MPI to share bulk data between processes使用 MPI 在进程之间共享批量数据
【发布时间】:2021-09-22 22:17:16
【问题描述】:

我的主要问题是如何将自定义类型/结构的成员与通过 MPI_Win_allocate_shared(size,disp,...,&baseptr, &win) 分配的成员相关联。感谢 C 或 fortran 的帮助!下面我包含了我想在 C 和 fortran 中做的事情的草图。

C中的一个例子大致如下:

struct MyStruct{
    int * ptr_int;
    double * ptr_dble;
};
main(){
    int n1,n2,n3;
    struct * data;
    // I am looking to use MPI to allocate a struct equivalent to the following:
    // data = calloc(n3,sizeof(struct MyStruct))
    // for (int i=0;i<n3;i++) {
    //     data[i].ptr_int = calloc(n1,sizeof(int));
    //     data[i].ptr_dble = calloc(n2,sizeof(double));}
    
    int w_size,w_rank;
    MPI_Init(NULL,NULL);
    MPI_Comm_size(MPI_COMM_WORLD,&w_size);
    MPI_Comm_rank(MPI_COMM_WORLD,&w_rank);

    MPI_Win win;
    MPI_Aint size;
    void * baseptr;
    if (w_rank==0){
        size = n3*(sizeof(int)*n1 + sizeof(double)*n2);
        MPI_Win_allocate_shared(size,1,MPI_INFO_NULL,MPI_COMM_WORLD,&baseptr,&win);
        // Question: how to associate struct * data with win, baseptr? 
        // Can &win then be initialized by calling data[i].ptr_int[j] = ...?
    }else{
        MPI_Win_shared_query(...);
        // Question: again, how to associated struct * data with win, baseptr?
    }
}

等价于fortran的一个例子如下:

type MyStruct
    integer, allocatable :: ptr_int(:)
    real, allocatable :: ptr_dble(:)
end type

program main 
    implicit none
    use mpi

    integer :: n1,n2,n3
    type(MyStruct), allocatable :: data

    integer :: w_rank, w_size, ierr 
    
    call mpi_init(ierr)
    call mpi_comm_size(mpi_comm_world,w_size,ierr)
    call mpi_comm_rank(mpi_comm_world,w_rank,ierr)

    MPI_Win MPI_Win 
    MPI_Aint size

    if (w_rank==0) then 
        size = n3*(sizeof(int)*n1 + sizeof(double)*n2)
        call mpi_win_allocate_shared(size,1,MPI_INFO_NULL,MPI_COMM_WORLD,baseptr,win)
        ! Question: how to associate data with win, baseptr? 
        ! Can win then be initialized by calling data(i)%ptr_int(j) = ...?
    else
        call mpi_win_shared_query(...);
        ! Question: again, how to associated type(mystruct) data with win, baseptr?
    endif

end program main

【问题讨论】:

  • 看看 MPI_Winn_allocate_shared 上的 openmpi 页面,我看到“MPI_Win_allocate_shared 是由 comm 组中的所有进程执行的集体调用” - 你只有一个进程调用它。它继续说“可以使用函数 MPI_Win_shared_query 查询其他进程的基本指针。”所以我从来没有这样做过,但在我看来 win_allocate_shared 为您提供了窗口所有 procs 的句柄,然后查询将进程特定指针作为 void * 返回。
  • 另外请注意,我希望您不想从远程进程访问 calloc 分配的内存。指针将是仅在分配进程空间中有意义的地址 - 谁知道它们将指向另一个进程的位置。
  • 最后我看到 Fortran 标记已被删除 - 如果您对 Fortran 解决方案感到满意,我建议您编辑问题以明确说明并重新添加 Fortran 标记。

标签: c fortran mpi


【解决方案1】:

感谢早先在MPI-3 Shared Memory for Array Struct 发布的类似问题,我解决了问题的 C 部分。我仍然需要在与我目前的工作更相关的 fortran 中实现它。

关键方面是可以在每个 MPI 进程中定义指向结构的指针,并使用指针算法将共享内存与数据结构相关联。一个完整的C解决方案如下:

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

struct product{
    int nint;
    int ndble;
    int * ptr_int;
    double * ptr_dble;
};

int main(){
    int n1,n2,nproduct;

    n1 = 3;
    n2 = 4;
    nproduct = 2;
    struct product * tmp = calloc(nproduct,sizeof(struct product));

    // Initiate MPI 
    int world_size,world_rank;
    int disp_unit;
    MPI_Win win;
    MPI_Aint size;
    void * baseptr;
    
    MPI_Init(NULL,NULL);
    MPI_Comm_size(MPI_COMM_WORLD,&world_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    printf("Hello world from rank %d out of %d processors\n",world_rank,world_size);

    if (world_rank==0){
            size = (sizeof(int)*n1 + sizeof(double)*n2) * nproduct;
        disp_unit = 1;
        MPI_Win_allocate_shared(size,disp_unit,MPI_INFO_NULL,MPI_COMM_WORLD,&baseptr, &win);
        printf("Success allocation\n");
    }
    else{
        MPI_Win_allocate_shared(0,1,MPI_INFO_NULL,MPI_COMM_WORLD,&baseptr,&win);
        MPI_Win_shared_query(win,0,&size,&disp_unit,&baseptr);
        printf("Success query\n");
    }

    for (int i=0;i<nproduct;i++){
        tmp[i].nint = n1;
        tmp[i].ndble = n2;
        tmp[i].ptr_int = (int*) baseptr;
        tmp[i].ptr_dble = (double *) (baseptr + sizeof(int)*n1);
    }

    if (world_rank==0){
        //MPI_Win_lock(MPI_LOCK_EXCLUSIVE,0,MPI_MODE_NOCHECK,win);
        for (int i =0;i<nproduct;i++){
            // initialize data stored in win via tmp
            for (int j =0;j<n1;j++){
                tmp[i].ptr_int[j] = j;
            }
            for (int j=0;j<n2;j++){
                tmp[i].ptr_dble[j] = 2*(j-3);
            }
        }
        //MPI_Win_unlock(0,win);
    }

    MPI_Barrier(MPI_COMM_WORLD);

    // test
    if (world_rank==1){
        for (int j =0;j<n1;j++){
            printf("%d ",tmp[1].ptr_int[j]);
        }
        printf("\n");
        for (int j=0;j<n2;j++){
            printf("%f ",tmp[1].ptr_dble[j]);
        }
        printf("\n");
    }

    MPI_Win_free(&win);
    MPI_Finalize();
}

【讨论】:

  • 在 Fortran 中并没有太大的不同。查看标准互操作库iso_c_binding 提供的调用。 c_sizeof() 用于计算存储大小,c_f_pointer() 用于将内存地址分配给 Fortran 指针变量。
猜你喜欢
  • 2016-10-05
  • 1970-01-01
  • 1970-01-01
  • 2012-04-09
  • 1970-01-01
  • 2016-12-14
  • 2012-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多