我正在做一个学习MPI单边通信的程序。在程序中,每个进程接收一个具有N个键、值对的本地数组。局部N可以变化,因此每个进程可以有不同大小的数组。程序应该对数组进行排序,使得进程0得到所有键为0的值,进程1得到所有键为1的值,以此类推,直到进程P-1。
我的策略是首先让每个进程运行它们的本地数组,并计算它们在一个名为local_counts的本地数组中为每个进程拥有多少值。然后我使用MPI_Allreduce来查找数组global_counts中的全局计数。然后,我使用MPI_Exscan来查找前缀和,这样我就知道每个进程应该在另一个进程的RMA窗口中放置数组的哪些索引。
我创建了一个大小合适的window_buffer,创建了一个RMA窗口,使用MPI_fence来开始和结束一个epoch,在epoch内部,我遍历了本地数组,并将值i放在正确进程的RMA窗口的正确索引中。
当我用1个进程测试它时,它工作得很好。然而,它似乎不能与多个进程一起工作,这有点违背了这一点。我在这里做错了什么,它不适用于多个进程?我会发布确切的输出,但我使用的是一个自动评分器,它提供的反馈非常有限。它只告诉我,我在正确排序的值,这可能意味着一个segfault或错误的答案。我知道它确实适用于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);
}
sort.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
1条答案
按热度按时间iugsix8n1#
我认为你的逻辑有错误。在将数据放到
target_rank
上之后,您可以更新prefix_global_sum[target_rank]
。但是,如果另一个进程将数据放在同一个级别上呢?你的信息就不再正确了。解决这个问题的方法是让每个进程维护自己的
prefix_global_sum
值,当你想把数据放在那个进程上时,你首先必须从那个目标排名中查询那个值。