我正在开发一个学习 MPI 单向通信的程序。在程序中,每个进程接收一个包含 N 个键、值对的本地数组。本地 N 可以变化,因此每个进程可以有不同大小的数组。程序应该对数组进行排序,以便进程 0 获取所有具有键 0 的值,进程 1 应该获取所有具有键 1 的值,依此类推,直到处理 P-1。
我的策略是首先让每个进程运行其本地数组,并在名为 local_counts 的本地数组中计算每个进程拥有多少个值。然后我使用 MPI_Allreduce 查找数组 global_counts 中的全局计数。然后我使用 MPI_Exscan 查找前缀和,以便我知道每个进程应该在另一个进程的 RMA 窗口中放置一个值的数组索引。
我创建具有适当大小的 window_buffer,创建 RMA 窗口,使用 MPI_fence 开始和结束一个纪元,并在纪元内我遍历本地数组并将值 i 放置在正确进程的 RMA 窗口的正确索引中。
当我用 1 个进程测试它时,效果很好。然而,它似乎不适用于多个进程,这有点违背了这一点。我在这里做错了什么,它不适用于超过 1 个进程?我会发布确切的输出,但我使用的自动评分器提供的反馈极其有限。它只告诉我,我已经正确地对值进行了排序,这可能意味着段错误或错误的答案。我知道它确实适用于 1 个进程。谢谢!
我的程序,sort.cpp:
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <mpi.h>
#include "helper.h"
#include "sort.h"
void my_sort(int N, item *myItems, int *nOut, item **myResult)
{
int rank, nprocs;
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int local_counts[nprocs] = {0};
int global_counts[nprocs] = {0};
int prefix_global_sum[nprocs] = {0};
for (int i = 0; i < N; i++)
{
int key = myItems[i].key;
local_counts[key]++;
}
fprintf(stdout, "Initial array: ");
for (int i = 0; i < N; i++)
{
fprintf(stdout, "%d ", myItems[i].value);
}
fprintf(stdout, "\n");
MPI_Allreduce(local_counts, global_counts, nprocs, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
MPI_Exscan(local_counts, prefix_global_sum, nprocs, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (rank == 0)
{
for (int i = 0; i < nprocs; i++)
{
prefix_global_sum[i] = 0;
}
}
*nOut = global_counts[rank];
item *window_buffer[*nOut] = {0};
MPI_Win window;
*myResult = (item *)malloc(*nOut * sizeof(item));
MPI_Win_create((*myResult), (MPI_Aint)*nOut * sizeof(item), sizeof(item), MPI_INFO_NULL, MPI_COMM_WORLD, &window);
MPI_Win_fence(0, window);
for (int i = 0; i < N; i++)
{
val* value = &myItems[i].value;
int target_rank = myItems[i].key;
int target_offset = prefix_global_sum[target_rank];
MPI_Put(value, sizeof(item), MPI_BYTE, target_rank, target_offset, sizeof(item), MPI_BYTE, window);
prefix_global_sum[target_rank] += 1;
}
MPI_Win_fence(0, window);
MPI_Win_free(&window);
}
排序.h:
#ifndef SORT_H
#define SORT_H
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream> // for debugging, if you like
#include <mpi.h>
#include "helper.h"
void my_sort(int N, item *myItems, int *nOut, item **myResult);
#endif
我认为你的逻辑有问题。将数据放入
prefix_global_sum[target_rank]
后即可更新 target_rank
。但是,如果另一个进程将数据放在同一等级上怎么办?那么您的信息就不再正确了。
解决此问题的方法是让每个进程维护自己的
prefix_global_sum
值,当您想要将数据放入该进程时,您首先必须从该目标排名查询该值。