C++ OpenMPI:MPI_Send分配越来越多的内存

C++ OpenMPI:MPI_Send分配越来越多的内存,c++,memory,mpi,send,openmpi,C++,Memory,Mpi,Send,Openmpi,我目前正在编写一段代码,该代码在MPI通信过程中由于内存不足而在一段时间后崩溃。我想知道为什么代码使用越来越多的内存,因为我试图尽可能减少分配。我的一所大学的代码也有类似的问题 所以我发现这似乎是由我的send和recv例程引起的,因此我写了一个示例,显示了类似的行为(在较小的范围内): 所需的内存随着涉及更多内核而增加。因此,send和recv函数似乎分配了越来越多的内存。将输出放入循环表明附加内存不是分配一次,而是分配了几次(但并不总是) 我已经用几个MPI和GCC版本对此进行了测试,例如G

我目前正在编写一段代码,该代码在MPI通信过程中由于内存不足而在一段时间后崩溃。我想知道为什么代码使用越来越多的内存,因为我试图尽可能减少分配。我的一所大学的代码也有类似的问题

所以我发现这似乎是由我的send和recv例程引起的,因此我写了一个示例,显示了类似的行为(在较小的范围内):

所需的内存随着涉及更多内核而增加。因此,send和recv函数似乎分配了越来越多的内存。将输出放入循环表明附加内存不是分配一次,而是分配了几次(但并不总是)

我已经用几个MPI和GCC版本对此进行了测试,例如GCC 4.9.2和MPI 1.8.3。所需的额外内存量似乎随所选版本而异

有人知道为什么会发生这种情况,特别是我如何解决这个问题吗

非常感谢您的帮助和良好祝愿


Klaus

库维护多个动态大小的缓冲区。有太多的参数可用于调整这些缓冲区的大小(
ompi_info--all | grep buffer
,以便快速体验),我不建议您更改它们的值。除非RSS增量与发送/接收的数量成线性增加,并且似乎没有达到某个极限,否则我不会担心。我赞同@HristoIliev的建议。如果不使用缓冲通信,则已处于“缓冲区最少”区域;)。尝试改进MPI实现的默认行为确实很难,而且很少能做得更好。谢谢您的回答。我尝试自己使用MPI_Ibsend设置缓冲区,但这似乎没有改变任何事情。问题是,在某个时刻,我的程序内存不足,因此崩溃。我可以以某种方式保存所有中间阶段,然后重新运行程序,但我更希望程序能够在没有此类问题的情况下完成……内存不足的许多方法中,有一种额外表明MPI是罪魁祸首,那就是让
MPI_*发送
与足够的
MPI_*接收
匹配。数据必须在某个地方进行缓冲。如果您使用
MPI_I*Send
MPI_I*Receive
可以自己控制内存,甚至可以避免分配。像“英特尔跟踪分析器”这样的工具可以指向不匹配的发送。代码可能会死锁,因为它可以等待
MPI\u发送()
完成,而匹配的
MPI\u Recv()
不会发布。因此,您隐式地依赖于内部缓冲(这节省了您的时间),但抱怨它使用内存。。。只需使用
MPI\u Irevc()
然后使用
MPI\u Ssend()
MPI\u Issend()
MPI\u Waitall()
修复代码即可。这将提高性能并避免缓冲。库维护多个动态大小的缓冲区。有太多的参数可用于调整这些缓冲区的大小(
ompi_info--all | grep buffer
,以便快速体验),我不建议您更改它们的值。除非RSS增量与发送/接收的数量成线性增加,并且似乎没有达到某个极限,否则我不会担心。我赞同@HristoIliev的建议。如果不使用缓冲通信,则已处于“缓冲区最少”区域;)。尝试改进MPI实现的默认行为确实很难,而且很少能做得更好。谢谢您的回答。我尝试自己使用MPI_Ibsend设置缓冲区,但这似乎没有改变任何事情。问题是,在某个时刻,我的程序内存不足,因此崩溃。我可以以某种方式保存所有中间阶段,然后重新运行程序,但我更希望程序能够在没有此类问题的情况下完成……内存不足的许多方法中,有一种额外表明MPI是罪魁祸首,那就是让
MPI_*发送
与足够的
MPI_*接收
匹配。数据必须在某个地方进行缓冲。如果您使用
MPI_I*Send
MPI_I*Receive
可以自己控制内存,甚至可以避免分配。像“英特尔跟踪分析器”这样的工具可以指向不匹配的发送。代码可能会死锁,因为它可以等待
MPI\u发送()
完成,而匹配的
MPI\u Recv()
不会发布。因此,您隐式地依赖于内部缓冲(这节省了您的时间),但抱怨它使用内存。。。只需使用
MPI\u Irevc()
然后使用
MPI\u Ssend()
MPI\u Issend()
MPI\u Waitall()
修复代码即可。这既可以提高性能,又可以避免缓冲。
#include <mpi.h>
#include <stdio.h>
#include <sys/resource.h>
#include <iomanip>

rusage mem_usage;
int mem_proc;
int mem_max;
int mem_min;
int mem_sum;
int mem_sum_old;
double mem_avg;

int world_size;
int world_rank;


void PrintMemUsage(std::string prefix)
{
    MPI_Barrier(MPI_COMM_WORLD);

    getrusage( RUSAGE_SELF, &mem_usage);

    mem_proc = mem_usage.ru_maxrss;

    MPI_Allreduce(&mem_proc,&mem_sum,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
    MPI_Allreduce(&mem_proc,&mem_min,1,MPI_INT,MPI_MIN,MPI_COMM_WORLD);
    MPI_Allreduce(&mem_proc,&mem_max,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);


    mem_avg = ((double) mem_sum) / ((double) world_size);

    if(mem_sum_old == 0)
        mem_sum_old = mem_sum;

    if(world_rank == 0) std::cout << "("<< world_rank << ") " << std::setw(50) << std::left << prefix << " MEM: " << mem_sum << " KB.  MIN: " << mem_min << " MAX: " << mem_max << " AVG: " << mem_avg << " Change: " << (mem_sum)-(mem_sum_old) << " KB" << std::endl;
    mem_sum_old = mem_sum;
}


int main(int argc, char** argv) {
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

    double send = 42.0;
    double recv = 1;
    int i;
    MPI_Request Request[2];

    PrintMemUsage("start");

    for(i = 0; i < 10000; ++i)
    {
        MPI_Send (&send, 1, MPI_DOUBLE, (world_rank+1)%world_size, i, MPI_COMM_WORLD);
        MPI_Recv (&recv, 1, MPI_DOUBLE, (world_rank-1)%world_size, i, MPI_COMM_WORLD, MPI_STATUS_IGNORE);           
    }

    PrintMemUsage("end");

    MPI_Finalize();
}
mpirun -np 2 ./test
(0) start                                              MEM: 53068 KB.  MIN: 26528 MAX: 26540 AVG: 26534 Change: 0 KB
(0) end                                                MEM: 53300 KB.  MIN: 26632 MAX: 26668 AVG: 26650 Change: 232 KB