2013-04-22 134 views
6

我有以下情况:我已经写了一些简短的MPI测试代码,以便找出哪些组合的发送和接收操作在我的代码中效果最好。C++:奇怪的指针损坏错误

该代码在我自己的计算机上工作得很好(使用8个进程进行测试),但只要我运行一个正在处理的群集,就会得到一个巨大的错误输出,这是输出:http://pastebin.com/pXTRSf89

我在我的代码中做的事情如下:我打电话给我的通信功能100K次,并测量时间。该功能如下所示。我发现,错误总是发生在同一次迭代中(大约6K左右)。报告的处理器ID确实会改变。迭代是相同的,即使我使用64个proc而不是8个。问题是:我完全不知道,可能是错误的,特别是因为没有指针被释放或分配。

void communicateGrid(int level, real* grid, const Subdomain& subdomain, std::vector<TimeMap>& tm_) { 
    tm_[level]["CommGrid"].start(); 

    MPI_Status status[2]; 
    MPI_Request request[2]; 

    // x 
    MPI_Isend(&grid[getIndexInner(level, 1, 1, 1) + innerGridpoints_[level][0] - numOuterGridpoints_[level]], 1, mpiTypes_[level * 4 + 1], subdomain.upperNeighbors[0], 0, MPI_COMM_WORLD, &request[0]); 
    MPI_Isend(&grid[getIndexInner(level, 1, 1, 1)], 1, mpiTypes_[level * 4 + 1], subdomain.lowerNeighbors[0], 1, MPI_COMM_WORLD, &request[1]); 

    MPI_Recv(&grid[getIndexInner(level, 1,1,1) + innerGridpoints_[level][0]], 1, mpiTypes_[level * 4 + 1], subdomain.upperNeighbors[0], 1, MPI_COMM_WORLD, &status[0]); 
    MPI_Recv(&grid[getIndexInner(level, 1,1,1) - numOuterGridpoints_[level]], 1, mpiTypes_[level * 4 + 1], subdomain.lowerNeighbors[0], 0, MPI_COMM_WORLD, &status[1]); 

    //y 
    MPI_Isend(&grid[getIndex(level, 0, innerGridpoints_[level][1], 0)], 1, mpiTypes_[level * 4 + 2], subdomain.upperNeighbors[1], 2, MPI_COMM_WORLD, &request[0]); 
    MPI_Isend(&grid[getIndex(level, 0, numOuterGridpoints_[level], 0)], 1, mpiTypes_[level * 4 + 2], subdomain.lowerNeighbors[1], 3, MPI_COMM_WORLD, &request[1]); 

    MPI_Recv(&grid[getIndex(level, 0, innerGridpoints_[level][1] + numOuterGridpoints_[level], 0)], 1, mpiTypes_[level * 4 + 2], subdomain.upperNeighbors[1], 3, MPI_COMM_WORLD, &status[0]); 
    MPI_Recv(grid, 1, mpiTypes_[level * 4 + 2], subdomain.lowerNeighbors[1], 2, MPI_COMM_WORLD, &status[1]); 

    // z 
    MPI_Isend(&grid[getIndex(level, 0, 0, innerGridpoints_[level][2])], 1, mpiTypes_[level * 4 + 3], subdomain.upperNeighbors[2], 4, MPI_COMM_WORLD, &request[0]); 
    MPI_Isend(&grid[getIndex(level, 0, 0, numOuterGridpoints_[level])], 1, mpiTypes_[level * 4 + 3], subdomain.lowerNeighbors[2], 5, MPI_COMM_WORLD, &request[1]); 

    MPI_Recv(&grid[getIndex(level, 0, 0, numOuterGridpoints_[level] + innerGridpoints_[level][2])], 1, mpiTypes_[level * 4 + 3], subdomain.upperNeighbors[2], 5, MPI_COMM_WORLD, &status[0]); 
    MPI_Recv(grid, 1, mpiTypes_[level * 4 + 3], subdomain.lowerNeighbors[2], 4, MPI_COMM_WORLD, &status[1]); 

    tm_[level]["CommGrid"].stop(); 
} 

mpiTypes_的类型是MPI_Datatype *的全局变量,innerGridpoints_和numOuterGridpoints_是全球性的(我知道这是不是一个好的编码风格,但我把它仅适用于正时)。 我很确定我的数据类型是正确的,因为他们在另一个通信功能设置中工作(例如Irecv后面跟着发送)。

Final注意:我只是试图用一个进程来运行它。然后将下面的出错:

排名0 [周一年04月22 2时11分23秒2013] [c0-0c1s3n0]致命错误 PMPI_Isend:内部MPI错误!错误堆栈:PMPI_Isend(148): MPI_Isend(buf = 0x2aaaab7b531c,count = 1,dtype = USER,dest = 0, tag = 1,MPI_COMM_WORLD,请求= 0x7fffffffb4d4)失败(未知)(): 内部MPI错误! _pmiu_daemon(SIGCHLD):NID 00070] [c0-0c1s3n0] [周一年04月22二点11分23秒2013] PE RANK 0退出信号中止

再次,这仅发生在群集上,但制作我的机器。

我很高兴能够检查任何事情或错误可能在哪里! 谢谢

+0

它工作在哪种品牌的CPU上,哪种品牌的CPU不起作用? – Patashu 2013-04-22 00:29:37

+0

我想知道你的指针是否最终会指向它们不应该有的数据块。当你做'&grid [getIndex(level,0,0,numOuterGridpoints_ [level] + innerGridpoints_ [level] [2])]''这样的事情时,是否有机会指向一个不是你自己的块?或者你所调用的函数中是否有内存泄漏......是两台机器上的编译器/库的完全相同版本吗? – Floris 2013-04-22 00:32:39

+0

getIndex和getInnerIndex只是内联索引函数,因为网格是3d数组,它们应该没问题。我的电脑是英特尔i5,使用gcc 4.6.0(Mac系统)进行编译 - 集群是带有Opteron CPU的Cray机器。我尝试过,但标准的PGI编译器以及gcc(版本4.6.3) – Chris 2013-04-22 00:37:44

回答

2

您必须等待或测试或由MPI_Isend()创建的MPI请求上的东西,否则您将泄漏内部资源,并最终崩溃,这就是发生了什么事情。

Jeff Squyres在他的blog post at Cisco中表现很好。

知道,那些Isends正在完成,但MPI库没有知道这和清理分配资源的方式,并指出这些MPI_Request秒。需要多少资源和哪种资源取决于很多事情,包括底层网络连接(例如可能占用稀缺的infiniband资源),因此它在您自己的机器上工作而不是在群集上工作并不一定意外。

您可以通过MPI_Isend/MPI_Recv() s各自阶段之后加入

MPI_Waitall(2, request, status); 

解决这个问题。

这不仅仅是清理资源所必需的,它实际上还需要一个具有非阻塞请求的程序的正确性。

+0

的确,现在它的工作,谢谢。从来不知道这是必要的,我一直认为你可以避免等待,如果你知道所有得到正确接收 – Chris 2013-04-24 09:41:35