使计算节点中的所有处理器在 OpenMPI 中读取相同的内存块
Making all processors in a computing node read the same memory block in OpenMPI
我想 运行 使用 OpenMPI 和 C 在计算集群中进行数值模拟。但是,有一个大矩阵 A
在每个处理器中都是恒定且相等的。为了避免分配太多不必要的内存,我想将具有共享内存(即它们在同一计算节点中)的处理器分组,并且每个节点 malloc 中只有一个处理器并设置那个大矩阵 A
.然后节点中的所有其他处理器应该能够读取该矩阵。
This other question 正是我所需要的,但它是在 Fortran 中。我接受了它的回答并用 C 做了一个原型,但它没有按预期工作。由于我无法理解的原因,MPI_Win_allocate_shared
返回的内存地址偏移了 1 个位移单位。请参阅下面的代码:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int
main ()
{
MPI_Init(NULL, NULL);
int num_processors;
MPI_Comm_size(MPI_COMM_WORLD, &num_processors);
int proc_global_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &proc_global_rank);
// Split de global communicator, grouping by shared memory
MPI_Comm compute_comm;
MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &compute_comm);
int proc_compute_rank;
MPI_Comm_rank(compute_comm, &proc_compute_rank);
// Create the window
const int ARRAY_SIZE = 1;
int* shared_data;
MPI_Aint shared_data_size;
if (proc_compute_rank == 0) {
shared_data_size = ARRAY_SIZE * sizeof(int);
} else {
shared_data_size = 0;
}
int disp_unit = sizeof(int);
MPI_Win window;
MPI_Win_allocate_shared(shared_data_size, disp_unit, MPI_INFO_NULL, compute_comm, &shared_data, &window);
if (proc_compute_rank == 0) {
shared_data[0] = -10;
}
// get the location of the shared memory segment
if (proc_compute_rank != 0) {
MPI_Win_shared_query(window, 0, &shared_data_size, &disp_unit, shared_data);
}
MPI_Win_fence(0, window); // wait for shared variables to be ready to be used
MPI_Barrier(compute_comm);
printf("rank %d, value[0] = %d\n", proc_compute_rank, shared_data[0]); // prints a wrong value
printf("rank %d, value[-1] = %d\n", proc_compute_rank, shared_data[-1]); // prints correct value
// do calculations...
MPI_Win_fence(0, window); // wait for shared variables to be no longer needed
MPI_Barrier(compute_comm);
MPI_Win_free(&window);
MPI_Finalize();
return EXIT_SUCCESS;
}
你的代码中真正的问题是你传递了一个 int*
到 MPI_Win_query
,但是那个调用需要设置指针,所以你需要传递一个 int**
,这意味着在你的情况下 &shared_data
.
可能存在第二个问题:通过显式设置 window 缓冲区的内容,您假设是“统一内存模型”,这很可能就是这种情况。如有疑问,请测试
MPI_Win_get_attr(the_window,MPI_WIN_MODEL,&modelstar,&flag);
并确保该参数不是 MPI_WIN_SEPARATE
,在这种情况下,您必须 MPI_Put
将数据放入 window。
顺便说一句,您对获取不同地址的进程进行了观察。即使在你修复了你的&符号错误之后,这仍然是正确的!程序员认为的地址只是一个 逻辑地址 ,它被“页面 table” 翻译成 物理地址 .但是每个进程都有自己的页面table,所以相同的物理地址会在进程中转换为不同的逻辑地址,所以,是的,即使你有正确的指针,你也会得到不同的十六进制地址。
我想 运行 使用 OpenMPI 和 C 在计算集群中进行数值模拟。但是,有一个大矩阵 A
在每个处理器中都是恒定且相等的。为了避免分配太多不必要的内存,我想将具有共享内存(即它们在同一计算节点中)的处理器分组,并且每个节点 malloc 中只有一个处理器并设置那个大矩阵 A
.然后节点中的所有其他处理器应该能够读取该矩阵。
This other question 正是我所需要的,但它是在 Fortran 中。我接受了它的回答并用 C 做了一个原型,但它没有按预期工作。由于我无法理解的原因,MPI_Win_allocate_shared
返回的内存地址偏移了 1 个位移单位。请参阅下面的代码:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int
main ()
{
MPI_Init(NULL, NULL);
int num_processors;
MPI_Comm_size(MPI_COMM_WORLD, &num_processors);
int proc_global_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &proc_global_rank);
// Split de global communicator, grouping by shared memory
MPI_Comm compute_comm;
MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &compute_comm);
int proc_compute_rank;
MPI_Comm_rank(compute_comm, &proc_compute_rank);
// Create the window
const int ARRAY_SIZE = 1;
int* shared_data;
MPI_Aint shared_data_size;
if (proc_compute_rank == 0) {
shared_data_size = ARRAY_SIZE * sizeof(int);
} else {
shared_data_size = 0;
}
int disp_unit = sizeof(int);
MPI_Win window;
MPI_Win_allocate_shared(shared_data_size, disp_unit, MPI_INFO_NULL, compute_comm, &shared_data, &window);
if (proc_compute_rank == 0) {
shared_data[0] = -10;
}
// get the location of the shared memory segment
if (proc_compute_rank != 0) {
MPI_Win_shared_query(window, 0, &shared_data_size, &disp_unit, shared_data);
}
MPI_Win_fence(0, window); // wait for shared variables to be ready to be used
MPI_Barrier(compute_comm);
printf("rank %d, value[0] = %d\n", proc_compute_rank, shared_data[0]); // prints a wrong value
printf("rank %d, value[-1] = %d\n", proc_compute_rank, shared_data[-1]); // prints correct value
// do calculations...
MPI_Win_fence(0, window); // wait for shared variables to be no longer needed
MPI_Barrier(compute_comm);
MPI_Win_free(&window);
MPI_Finalize();
return EXIT_SUCCESS;
}
你的代码中真正的问题是你传递了一个 int*
到 MPI_Win_query
,但是那个调用需要设置指针,所以你需要传递一个 int**
,这意味着在你的情况下 &shared_data
.
可能存在第二个问题:通过显式设置 window 缓冲区的内容,您假设是“统一内存模型”,这很可能就是这种情况。如有疑问,请测试
MPI_Win_get_attr(the_window,MPI_WIN_MODEL,&modelstar,&flag);
并确保该参数不是 MPI_WIN_SEPARATE
,在这种情况下,您必须 MPI_Put
将数据放入 window。
顺便说一句,您对获取不同地址的进程进行了观察。即使在你修复了你的&符号错误之后,这仍然是正确的!程序员认为的地址只是一个 逻辑地址 ,它被“页面 table” 翻译成 物理地址 .但是每个进程都有自己的页面table,所以相同的物理地址会在进程中转换为不同的逻辑地址,所以,是的,即使你有正确的指针,你也会得到不同的十六进制地址。