作为MPI内存窗口共享的值的同步存在问题。使用共享内存的原因是内存结构太大,无法在每个进程上都有副本,但是需要分配其元素的计算。因此,想法是每个节点只有一个数据结构。
这是代码的简化版本,其中包含应描述问题的最小子集。我跳过了在节点之间进行同步的部分。
我有两个问题:
我尝试使用主动目标同步(MPI_Win_Fence()),但是会出现相同的问题。由于我没有太多经验,可能是我只是使用了错误的方法。
MPI_Comm nodecomm;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, rank,
MPI_INFO_NULL, &nodecomm);
MPI_Comm_size(nodecomm, &nodesize);
MPI_Comm_rank(nodecomm, &noderank);
int local_xx_size = 0;
if (noderank == 0){
local_xx_size = xx_size;
}
MPI_Win win_xx;
MPI_Aint winsize;
double *xx, *local_xx;
MPI_Win_allocate_shared(local_xx_size*sizeof(double), sizeof(double),
MPI_INFO_NULL, nodecomm, &local_xx, &win_xx);
xx = local_xx;
if (noderank != 0){
MPI_Win_shared_query(win_xx, 0, &winsize, &windisp, &xx);
}
//init xx
if(noderank == 0){
MPI_Win_lock_all(0, win_xx);
for (i=0; i<xx_size; i++){
xx[i]=0.0;
}
MPI_Win_unlock_all(win_xx);
}
MPI_Barrier(nodecomm);
long counter = 0;
for(i = 0; i < largeNum; i++) {
//some calculations
for(j = 0; j < xx_size; j++) {
//calculate res
MPI_Win_lock_all(0, win_xx);
xx[counter] += res; //update value
MPI_Win_unlock_all(win_xx);
}
}
MPI_Barrier(nodecomm);
//use xx (sync data from all the nodes)
MPI_Win_free(&win_xx);
对于这些问题的任何帮助和建议,我将不胜感激。
答案 0 :(得分:0)
MPI锁定/解锁本身不会导致原子更新。
无论如何,您不应使用过多的锁定/解锁功能。请改用冲洗。分配和释放窗口时,只能锁定和解锁窗口。
您可以使用MPI累加函数(Accumulate,Get_accumulate,Fetch_and_op,Compare_and_swap)获得原子性,或者-仅在共享内存的情况下-可以使用与编译器关联的原子基元。由于C11 / C ++ 11需要类型,因此这对于C11 / C ++ 11来说有点棘手,因此,我在下面的示例中展示了大多数(即使不是全部)通用编译器都应使用的内在函数。
我不知道这是否正确。它仅演示了上面提到的概念。
MPI_Comm nodecomm;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, rank,
MPI_INFO_NULL, &nodecomm);
MPI_Comm_size(nodecomm, &nodesize);
MPI_Comm_rank(nodecomm, &noderank);
int local_xx_size = 0;
if (noderank == 0){
local_xx_size = xx_size;
}
MPI_Win win_xx;
MPI_Aint winsize;
double *xx, *local_xx;
MPI_Win_allocate_shared(local_xx_size*sizeof(double), sizeof(double), MPI_INFO_NULL, nodecomm, &local_xx, &win_xx);
MPI_Win_lock_all(0, win_xx);
xx = local_xx;
if (noderank != 0){
MPI_Win_shared_query(win_xx, 0, &winsize, &windisp, &xx);
}
//init xx
if(noderank == 0){
for (i=0; i<xx_size; i++){
xx[i]=0.0;
}
}
MPI_Barrier(nodecomm);
long counter = 0;
for(i = 0; i < largeNum; i++) {
//some calculations
for(j = 0; j < xx_size; j++) {
//calculate res
// xx[counter] += res; //update value
#ifdef USE_RMA_ATOMICS
// check the arguments - I don't know if I calculate the target+displacement right
int target = counter/local_xx_size;
MPI_Aint disp = counter%local_xx_size;
MPI_Accumulate(&res, MPI_LONG, target, disp, 1, MPI_LONG, MPI_SUM, win_xx);
MPI_Win_flush(target, win_xx);
#else
# ifdef USE_NEWER_INTRINSICS // GCC, Clang, Intel support this AFAIK
__atomic_fetch_add (&xx[counter], res, __ATOMIC_RELAXED);
# else // GCC, Clang, Intel, IBM support this AFAIK
__sync_fetch_and_add(&xx[counter], res);
# endof
#endif
}
}
MPI_Barrier(nodecomm);
MPI_Win_unlock_all(win_xx);
MPI_Win_free(&win_xx);