我正在为并行计算类编写一些C ++ MPI代码。我的代码工作正常,我已经完成了分配,但是代码使用了我预期的更多内存。随着处理器数量的增加,每个节点的内存需求正在快速增长。这是我用过的第一个真正的C / C ++或MPI程序,所以我觉得某个地方有某种内存泄漏。有人可以看看这段代码并告诉我在哪里?每当我使用new创建变量时,我都会删除它,所以我不确定我还应该寻找什么。我想一些问题可能来自我正在创建的对象,但是这些对象的析构函数是否应该在其作用域的末尾调用以释放它们在堆上分配的任何内存?我来自一个沉重的Java背景,我的大部分C / C ++都是自学成才,所以做我自己的内存管理很难总结。
问题很简单。我有一个大小为MSIZE * MSIZE
的矩阵(存储为单维向量)。每个处理器负责一些连续的数据块。然后我运行500次迭代,其中每个非边缘元素A[r][c]
被设置为A[r][c], A[r+1][c], A[r-1][c], A[r][c+1], A[r-1][c-1]
的最大值。在完成该迭代的整个更新过程之前,不会存储A[r][c]
的新值。处理器必须将边界上的值传递给其他处理器。
这是我的代码(我认为问题出现在这里的某个地方,但是如果你想看到剩下的代码(主要是帮助和初始化函数)让我知道,我会发布它):
#include <math.h>
#include "mpi.h"
#include <iostream>
#include <float.h>
#include <math.h>
#include <assert.h>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
using namespace std;
#define MSIZE 4000
#define TOTAL_SIZE (MSIZE * MSIZE)
#define NUM_ITERATIONS 500
int myRank;
int numProcs;
int start, end;
int numIncomingMessages;
double startTime;
vector<double> a;
map<int, set<int> > neighborsToNotify;
/*
* Send the indices that have other processors depending on them to those processors.
* Once the messages have been sent, receive messages until we've received all the messages
* we are expecting to receive.
*/
void doCommunication(){
int messagesReceived = 0;
map<int, set<int> >::iterator iter;
for(iter = neighborsToNotify.begin(); iter != neighborsToNotify.end(); iter++){
int destination = iter->first;
set<int> indices = iter->second;
set<int>::iterator setIter;
for(setIter = indices.begin(); setIter != indices.end(); setIter++){
double val = a.at(*setIter);
MPI_Bsend(&val, 1, MPI_DOUBLE, destination, *setIter, MPI_COMM_WORLD);
}
MPI_Status s;
int flag;
MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &s);
while(flag){
double message;
MPI_Recv(&message, 1, MPI_DOUBLE, s.MPI_SOURCE, s.MPI_TAG, MPI_COMM_WORLD, &s);
a.at(s.MPI_TAG) = message;
messagesReceived++;
MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &s);
}
}
while(messagesReceived < numIncomingMessages){
MPI_Status s;
MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &s);
double message;
MPI_Recv(&message, 1, MPI_DOUBLE, s.MPI_SOURCE, s.MPI_TAG, MPI_COMM_WORLD, &s);
a.at(s.MPI_TAG) = message;
messagesReceived++;
}
}
/*
* Perform one timestep of iteration.
*/
void doIteration(){
int pos;
vector<double> temp;
temp.assign(end - start + 1, 0);
for(pos = start; pos <= end; pos++){
int i;
double max;
if(isEdgeNode(pos))
continue;
int dependents[4];
getDependentsOfPosition(pos, dependents);
max = a.at(pos);
for(i = 0; i < 4; i++){
if(isInvalidPos(dependents[i]))
continue;
max = std::max(max, a.at(dependents[i]));
}
temp.at(pos - start) = max;
}
for(pos = start; pos <= end; pos++){
if(! isEdgeNode(pos)){
a.at(pos) = temp.at(pos - start);
}
}
}
/*
* Compute the checksum for this processor
*/
double computeCheck(){
int pos;
double sum = 0;
for(pos = start; pos <= end; pos++){
sum += a.at(pos) * a.at(pos);
}
return sum;
}
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
findStartAndEndPositions();
initializeArray();
findDependentElements();
MPI_Barrier(MPI_COMM_WORLD);
if(myRank == 0){
startTime = MPI_Wtime();
}
int i;
for(i = 0; i < NUM_ITERATIONS; i++){
if(myRank == 0)
cout << ".";
doCommunication();
MPI_Barrier(MPI_COMM_WORLD);
doIteration();
}
double check = computeCheck();
double receive = 0;
MPI_Reduce(&check, &receive, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if(myRank == 0){
cout << "n = " << MSIZE << " and p = " << numProcs << "\n";
cout << "The total time was: " << MPI_Wtime() - startTime << " seconds \n";
cout << "The checksum was: " << receive << " \n";
}
MPI_Finalize();
return 0;
}
答案 0 :(得分:0)
我认为你没有内存泄漏。但你可以用valgrind测试这个。请注意输出看起来很可怕。
mpirun -n8 valgrind ./yourProgram
我认为原因是MPI。您使用缓冲发送,因此每个节点将生成一个自己的缓冲区,您拥有的节点越多,生成的缓冲区就越多。为了确保您的算法与内存相关,请使用无缓冲发送(仅用于调试目的,因为它会终止您的加速)。或者尝试增加矩阵,在您仅使用112 MB的时刻,这并不是真正的并行化问题。尝试找到一些大小,以便使用一个节点的几乎所有内存。