繁体   English   中英

C ++ MPI程序中可能发生内存泄漏?

[英]Possible Memory Leak in C++ MPI Program?

我正在为并行计算类编写一些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;
}

我认为您没有内存泄漏。 但是您可以使用valgrind进行测试。 请注意,输出看起来很可怕。

 mpirun -n8 valgrind ./yourProgram

我认为原因是MPI。 您使用缓冲发送,因此每个节点将生成一个自己的缓冲区,您拥有的节点越多,缓冲区就会越多。 为了确保您的算法相对于内存可扩展,请使用无缓冲发送(仅用于调试目的,因为这会降低您的加速速度)。 或者,尝试仅增加112 MB的矩阵,这实际上并不是并行化的问题。 尝试找到一些大小,以便使用一个节点的几乎所有内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM