高性能计算

open MPI MPI_Send recv 65536以上字节出错

2010年4月9日 阅读(433)

最近遇到一个超级难查的错误,一方面所因为程序所MPI并行程序,很难debug,基本没有啥可用的调试工具。其实之前用ubuntu编译完mpi程序后,执行即出现了错误,虽然没有解决,但我怀疑所环境问题。可能某些链接库的版本不对。
所以我用centos编译的open mpi是可以的,但是在将我的32位机与64位机并行时,在处理简单的程序时是没有问题的。
如下:
#include "mpi.h"
#include <stdio.h>
#include <math.h>
int main(int argc,char ** argv)
{
    int myid, numprocs;
    int  namelen;
    int type_size;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Get_processor_name(processor_name,&namelen);
    fprintf(stderr,"Hello World! Process %d of %d on %s\n",myid, numprocs, processor_name);

    long send = -1;
    if(myid == 0) send = 0;
    MPI_Bcast ( &send, 1, MPI_LONG, 0, MPI_COMM_WORLD);
    printf("rank:%d %ld",myid,send);

    MPI_Finalize();
}
这个程序没有问题,虽然接受结果不对,这是因为32位机上long是32位,但是64机上的long则是64位。

当我再次运行一个网络测试程序时,却出现如下错误:
[client:20895] *** Process received signal ***
[client:20895] Signal: Segmentation fault (11)
[client:20895] Signal code: Address not mapped (1)
[client:20895] Failing at address: 0x300a15b58
[client:20895] [ 0] [0x554d40]
[client:20895] [ 1] [0x47e0e8]
[client:20895] [ 2] [0x4512b3]
[client:20895] [ 3] [0x5275eb]
[client:20895] [ 4] [0x520e08]
[client:20895] [ 5] [0x4aa365]
[client:20895] [ 6] [0x42f05b]
[client:20895] [ 7] [0x403b1e]
[client:20895] [ 8] [0x401cb4]
[client:20895] [ 9] [0x400310]
[client:20895] [10] [0x555e40]
[client:20895] [11] [0x4001b9]
[client:20895] *** End of error message ***
————————————————————————–
mpirun noticed that process rank 1 with PID 20895 on node client exited on signal 11 (Segmentation fault).
上面所采用-static编译后的运行错误提示。

那个网络测试程序其实很简单,就算测试节点间的网络传输延时及速率。从0字节开始测,然后是100000字节,200000,300000………我们发现第一次测试可以正确完成。之后便失败。

于是怀疑与传输的字节大小有关,于是手工进行二分查找式的测试,从0->100000->50000->75000…….->65536,最后定位到16384个int也就是65536个字节。发现,16384之前大小的传送均是正确的,但是16385便开始出错了。

于是研究了这个16384,发现刚好是2的幂,这个发现让我很高兴,因为说明这个问题出现可能是有原因的。最后我怀疑这个值就是MPI_Send默认使用的系统缓存区的大小。当超过这个大小时,MPI_Send就down掉了。

虽然不确定更底层的原因。于是考虑采用另一种发送方式,MPI_Bsend,这样就可以利用我自己申请的缓存,而不受系统大小的限制了。经过实验发现可行。

同时为了验证这个猜想,将上面的简单程序,中发送的数据修改成65536byte,果然也down掉了。改成如下使用MPI_Bsend的形式,发现果然又可以了。

#include "mpi.h"
#include <stdio.h>
#include <math.h>
int main(int argc,char ** argv)
{
    int myid, numprocs;
    int  namelen;
    int type_size;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Comm comm = MPI_COMM_WORLD;
    MPI_Status status;

    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Get_processor_name(processor_name,&namelen);
    fprintf(stderr,"Hello World! Process %d of %d on %s\n",myid, numprocs, processor_name);

    MPI_Type_size(MPI_INT,&type_size);
    fprintf(stderr,"%s MPI_INT size:%d %d\n", processor_name,type_size,sizeof(int));
    MPI_Type_size(MPI_LONG,&type_size);
    fprintf(stderr,"%s MPI_LONG size:%d %d\n", processor_name,type_size,sizeof(long));
    MPI_Type_size(MPI_FLOAT,&type_size);
    fprintf(stderr,"%s MPI_FLOAT size:%d %d\n", processor_name,type_size,sizeof(float));
    MPI_Type_size(MPI_DOUBLE,&type_size);
    fprintf(stderr,"%s MPI_DOUBLE size:%d %d\n", processor_name,type_size,sizeof(double));
   
    int send = -1;

    int data_size = 8194,tag = 0;
    #define BUFFSIZE 1000000
    double *data_buffer = (double *)malloc(data_size*sizeof(double));   
    char *buffer = (char *)malloc(BUFFSIZE);
    int size;    

    MPI_Buffer_attach( buffer, BUFFSIZE);

    if(myid == 0)
        MPI_Bsend(data_buffer,data_size,MPI_DOUBLE,1,tag,comm);
    if(myid == 1)
        MPI_Recv(data_buffer,data_size,MPI_DOUBLE,0,tag,comm,&status);

    MPI_Buffer_detach(&buffer, &size);

    printf("rank:%d %d",myid,send);

    free(buffer);
    free(data_buffer);

    MPI_Finalize();
}

You Might Also Like