首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >阵列结构的MPI-3共享内存

阵列结构的MPI-3共享内存
EN

Stack Overflow用户
提问于 2016-07-05 22:18:06
回答 2查看 3K关注 0票数 2

我有一个简单的C++结构,它基本上包装了一个标准的C数组:

代码语言:javascript
复制
struct MyArray {
    T* data;
    int length;
    // ...
}

其中T是一个数字类型,如floatdoublelength是数组中的元素数。通常,我的数组非常大(数万到数千万元素)。

我有一个MPI程序,其中我希望通过MPI 3共享内存将MyArray的两个实例(比如a_olda_new )公开为共享内存对象。上下文是,每个MPI级别都从a_old读取。然后,每个MPI级别写入特定的a_new索引(每个级别只写入自己的一组索引--没有重叠)。最后,必须在所有级别设置a_old = a_newa_olda_new尺寸相同。现在,我通过同步(Isend/Irecv)实现代码的工作,每个等级的更新值与其他级别相同。但是,由于数据访问模式,我没有理由需要承担消息传递的开销,而是可以有一个共享内存对象,并在a_old = a_new之前设置一个屏障。我认为这会给我更好的表现(尽管如果我错了,请纠正我)。

我在找到使用MPI 3进行共享内存的完整代码示例时遇到了困难。大多数站点只提供参考文档或不完整的片段。有人能带我看一个简单而完整的代码示例吗?它完成了我想要实现的那种事情(通过MPI共享内存更新和同步一个数字数组)吗?我理解了创建共享内存通信器和窗口、设置围栏等主要概念,但如果能看到一个将所有内容组合在一起的示例,将有助于我理解这些概念。

另外,我应该提到,我将只在一个节点上运行我的代码,所以我不需要担心跨节点需要共享内存对象的多个副本;我只需要为运行MPI进程的单个节点提供数据的一个副本。尽管如此,在这种情况下,像OpenMP这样的其他解决方案对我来说是不可行的,因为我有大量的MPI代码,并且不能为了我想要共享的一两个数组而重写所有的东西。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-06 11:10:42

在MPI-3中使用共享内存相对简单.

首先,使用MPI_Win_allocate_shared分配共享内存窗口

代码语言:javascript
复制
MPI_Win win;
MPI_Aint size;
void *baseptr;

if (rank == 0)
{
   size = 2 * ARRAY_LEN * sizeof(T);
   MPI_Win_allocate_shared(size, sizeof(T), MPI_INFO_NULL,
                           MPI_COMM_WORLD, &baseptr, &win);
}
else
{
   int disp_unit;
   MPI_Win_allocate_shared(0, sizeof(T), MPI_INFO_NULL,
                           MPI_COMM_WORLD, &baseptr, &win);
   MPI_Win_shared_query(win, 0, &size, &disp_unit, &baseptr);
}
a_old.data = baseptr;
a_old.length = ARRAY_LEN;
a_new.data = a_old.data + ARRAY_LEN;
a_new.length = ARRAY_LEN;

在这里,只有排名0分配内存。在共享的情况下,哪个进程分配它并不重要。甚至可以让每个进程分配一部分内存,但是由于默认情况下分配是连续的,所以这两个方法是等价的。然后,所有其他进程都使用MPI_Win_shared_query来查找共享内存块开头的虚拟地址空间中的位置。该地址可能因级别而异,因此不应传递绝对指针。

现在,您可以简单地分别从a_old.data加载和存储到a_new.data中。由于在您的案例中的排名工作在不相交的一组内存位置,您实际上不需要锁定窗口。使用窗口锁来实现a_old或其他需要同步的操作的受保护初始化。您还可能需要显式地告诉编译器不要重新排序代码,并发出内存围栏,以便在调用MPI_Barrier()之前完成所有尚未完成的加载/存储操作。

a_old = a_new代码建议将一个数组复制到另一个数组上。相反,您可以简单地交换数据指针,并最终交换大小字段。由于只有数组的数据位于共享内存块中,所以交换指针是一种本地操作,即不需要同步。假设两个数组的长度相同:

代码语言:javascript
复制
T *temp;
temp = a_old.data;
a_old.data = a_new.data;
a_new.data = temp;

在继续之前,仍然需要一个屏障来确保所有其他进程都已经完成了处理。

在最末端,只需释放窗口:

代码语言:javascript
复制
MPI_Win_free(&win);

以下是一个完整的例子( C):

代码语言:javascript
复制
#include <stdio.h>
#include <mpi.h>

#define ARRAY_LEN 1000

int main (void)
{
   MPI_Init(NULL, NULL);

   int rank, nproc;
   MPI_Comm_rank(MPI_COMM_WORLD, &rank);
   MPI_Comm_size(MPI_COMM_WORLD, &nproc);

   MPI_Win win;
   MPI_Aint size;
   void *baseptr;

   if (rank == 0)
   {
      size = ARRAY_LEN * sizeof(float);
      MPI_Win_allocate_shared(size, sizeof(int), MPI_INFO_NULL,
                              MPI_COMM_WORLD, &baseptr, &win);
   }
   else
   {
      int disp_unit;
      MPI_Win_allocate_shared(0, sizeof(int), MPI_INFO_NULL,
                              MPI_COMM_WORLD, &baseptr, &win);
      MPI_Win_shared_query(win, 0, &size, &disp_unit, &baseptr);
   }

   printf("Rank %d, baseptr = %p\n", rank, baseptr);

   int *arr = baseptr;
   for (int i = rank; i < ARRAY_LEN; i += nproc)
     arr[i] = rank;

   MPI_Barrier(MPI_COMM_WORLD);

   if (rank == 0)
   {
      for (int i = 0; i < 10; i++)
         printf("%4d", arr[i]);
      printf("\n");
   }

   MPI_Win_free(&win);

   MPI_Finalize();
   return 0;
}

免责声明:带点盐把这个拿走。我对MPI的RMA的理解仍然很薄弱。

票数 7
EN

Stack Overflow用户

发布于 2016-07-06 07:32:23

这是一个为您提供描述的代码。在评论中,我对代码的描述很少。通常,它呈现一个动态的RMA窗口,内存必须分配到窗口。

来自MPI_Win_lock_all(0, win)打开MPI文档描述

使用锁类型MPI_LOCK_SHARED启动win中所有进程的RMA访问时代。在此期间,调用进程可以使用RMA操作访问win中所有进程的窗口内存。

在我使用MPI_INFO_NULL的地方,您可以使用MPI_Info对象向MPI提供其他信息,但这取决于您的内存访问模式。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

typedef struct MyArray {
    double* data;
    int length;
}MyArray;

#define ARRAY_SIZE 10

int main(int argc, char *argv[]) {
    int rank, worldSize, i;
    MPI_Win win;
    MPI_Aint disp;
    MPI_Aint *allProcessDisp;
    MPI_Request *requestArray;

    MyArray myArray;

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

    MPI_Win_create_dynamic(MPI_INFO_NULL, MPI_COMM_WORLD, &win);

    allProcessDisp = malloc(sizeof(MPI_Aint) * worldSize);

    requestArray = malloc(sizeof(MPI_Request) * worldSize);
    for (i = 0; i < worldSize; i++) 
        requestArray[i] = MPI_REQUEST_NULL;

    myArray.data = malloc(sizeof(double) * ARRAY_SIZE);
    myArray.length = ARRAY_SIZE;

    //Allocating memory for each process share window space 
    MPI_Alloc_mem(sizeof(double) * ARRAY_SIZE, MPI_INFO_NULL, &myArray.data);
    for (i = 0; i < ARRAY_SIZE; i++)
        myArray.data[i] = rank;

    //attach the allocating memory to each process share window space 
    MPI_Win_attach(win, myArray.data, sizeof(double) * ARRAY_SIZE);

    MPI_Get_address(myArray.data, &disp);

    if (rank == 0) {
        allProcessDisp[0] = disp;
        //Collect all displacements
        for (i = 1; i < worldSize; i++) {
            MPI_Irecv(&allProcessDisp[i], 1, MPI_AINT, i, 0, MPI_COMM_WORLD, &requestArray[i]);
        }
        MPI_Waitall(worldSize, requestArray, MPI_STATUS_IGNORE);
        MPI_Bcast(allProcessDisp, worldSize, MPI_AINT, 0, MPI_COMM_WORLD);
    }
    else {
        //send displacement 
        MPI_Send(&disp, 1, MPI_AINT, 0, 0, MPI_COMM_WORLD);
        MPI_Bcast(allProcessDisp, worldSize, MPI_AINT, 0, MPI_COMM_WORLD);
    }

    // here you can do RMA operations 
    // Each time you need an RMA operation you start with 
    double otherRankData = -1.0;
    int otherRank = 1;
    if (rank == 0) {
        MPI_Win_lock_all(0, win);
        MPI_Get(&otherRankData, 1, MPI_DOUBLE, otherRank, allProcessDisp[otherRank], 1, MPI_DOUBLE, win);
        // and end with 
        MPI_Win_unlock_all(win);
        printf("Rank 0 : Got %.2f from %d\n", otherRankData, otherRank);
    }

    if (rank == 1) {
        MPI_Win_lock_all(0, win);
        MPI_Put(myArray.data, ARRAY_SIZE, MPI_DOUBLE, 0, allProcessDisp[0], ARRAY_SIZE, MPI_DOUBLE, win);
        // and end with 
        MPI_Win_unlock_all(win);
    }

    printf("Rank %d: ", rank);
    for (i = 0; i < ARRAY_SIZE; i++)
        printf("%.2f ", myArray.data[i]);
    printf("\n");

    //set rank 0 array
    if (rank == 0) {
        for (i = 0; i < ARRAY_SIZE; i++)
            myArray.data[i] = -1.0;

        printf("Rank %d: ", rank);
        for (i = 0; i < ARRAY_SIZE; i++)
            printf("%.2f ", myArray.data[i]);
        printf("\n");
    }

    free(allProcessDisp);
    free(requestArray);
    free(myArray.data);

    MPI_Win_detach(win, myArray.data);
    MPI_Win_free(&win);
    MPI_Finalize();

    return 0;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38213745

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档