【发布时间】:2023-03-20 02:35:01
【问题描述】:
我正在使用 MPI-2 编写一个优化程序,其中我需要在所有进程之间共享一个相等长度的std::vectors(概念上)std::vector。该向量包含当前找到的问题的最佳k 解决方案,并且每次通过许多 MPI 进程之一找到新的最佳解决方案时都会更新。每个过程花费在寻找新解决方案上的时间通常差别很大。
我的问题是,考虑到同步和等待中的性能问题,每次找到新的最佳解决方案时,是否应该使用 MPI_allgather 等 MPI 集合;或者我应该在 MPI-2 中使用 One-Sided-Communications 来维护所有进程之间的“共享”向量。
特别是,如果我使用MPI_allgather,进程是否会提前完成其工作并等待与其他进程的某种同步?
我在 MPI 点对点通信(更新:以及 UPC)方面有一些工作经验,但在实际编码中没有使用集体或单方面的通信。我搜索了 SO 并找到了有关 MPI_allgathers 的相关问题/答案,例如Distribute a structure using MPI_Allgather ,以及关于片面沟通Creating a counter that stays synchronized across MPI processes。但是我很难说出这两种方法之间的确切区别。
谢谢,
--- 更新---
特别是,我在底部有来自Creating a counter that stays synchronized across MPI processes 的代码示例,它使用单面来维护单个int“共享”。我尝试将其调整为适用于泛型类型,但不知道如何使其工作,因为我无法理解原始代码以及它为什么维护数组data,以及如何将MPI_Accumulate 概括为用户函数(比如简单地将旧向量替换为新向量)。
template //注意:T 只能是原始类型(不能是指针、引用或结构),例如 int 和 double。
结构 mpi_array {
typedef std::vector 向量;
MPI_Win 获胜;
int 主机等级;
国际排名;
整数大小;
向量值;
向量 *hostvals;
};
单面通讯计数器代码:
#include <mpi.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
struct mpi_counter_t {
MPI_Win win;
int hostrank ;
int myval;
int *data;
int rank, size;
};
struct mpi_counter_t *create_counter(int hostrank) {
struct mpi_counter_t *count;
count = (struct mpi_counter_t *)malloc(sizeof(struct mpi_counter_t));
count->hostrank = hostrank;
MPI_Comm_rank(MPI_COMM_WORLD, &(count->rank));
MPI_Comm_size(MPI_COMM_WORLD, &(count->size));
if (count->rank == hostrank) {
MPI_Alloc_mem(count->size * sizeof(int), MPI_INFO_NULL, &(count->data));
for (int i=0; i<count->size; i++) count->data[i] = 0;
MPI_Win_create(count->data, count->size * sizeof(int), sizeof(int),
MPI_INFO_NULL, MPI_COMM_WORLD, &(count->win));
} else {
count->data = NULL;
MPI_Win_create(count->data, 0, 1,
MPI_INFO_NULL, MPI_COMM_WORLD, &(count->win));
}
count -> myval = 0;
return count;
}
int increment_counter(struct mpi_counter_t *count, int increment) {
int *vals = (int *)malloc( count->size * sizeof(int) );
int val;
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, count->hostrank, 0, count->win);
for (int i=0; i<count->size; i++) {
if (i == count->rank) {
MPI_Accumulate(&increment, 1, MPI_INT, 0, i, 1, MPI_INT, MPI_SUM,
count->win);
} else {
MPI_Get(&vals[i], 1, MPI_INT, 0, i, 1, MPI_INT, count->win);
}
}
MPI_Win_unlock(0, count->win);
count->myval += increment;
vals[count->rank] = count->myval;
val = 0;
for (int i=0; i<count->size; i++)
val += vals[i];
free(vals);
return val;
}
void delete_counter(struct mpi_counter_t **count) {
if ((*count)->rank == (*count)->hostrank) {
MPI_Free_mem((*count)->data);
}
MPI_Win_free(&((*count)->win));
free((*count));
*count = NULL;
return;
}
void print_counter(struct mpi_counter_t *count) {
if (count->rank == count->hostrank) {
for (int i=0; i<count->size; i++) {
printf("%2d ", count->data[i]);
}
puts("");
}
}
int test1() {
struct mpi_counter_t *c;
int rank;
int result;
c = create_counter(0);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
result = increment_counter(c, 1);
printf("%d got counter %d\n", rank, result);
MPI_Barrier(MPI_COMM_WORLD);
print_counter(c);
delete_counter(&c);
}
int test2() {
const int WORKITEMS=50;
struct mpi_counter_t *c;
int rank;
int result = 0;
c = create_counter(0);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
srandom(rank);
while (result < WORKITEMS) {
result = increment_counter(c, 1);
if (result <= WORKITEMS) {
printf("%d working on item %d...\n", rank, result);
sleep(random() % 10);
} else {
printf("%d done\n", rank);
}
}
MPI_Barrier(MPI_COMM_WORLD);
print_counter(c);
delete_counter(&c);
}
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
test1();
test2();
MPI_Finalize();
}
【问题讨论】:
-
您不能将 MPI_Accumulate 推广到任意(即非内置)类型,因为 MPI-3 不支持(它通常称为活动消息,您可以尝试 GASNet)。