代码之家  ›  专栏  ›  技术社区  ›  avgn

为什么在到达MEX文件的最后一行之后要花这么长时间才能返回Matlab?

  •  5
  • avgn  · 技术社区  · 7 年前

    当从matlab对MEX文件计时时:

    D=rand(14000)+rand(14000)*1i;
    tic;
    [A B C]=myMexFile(D);
    toc
    disp(datetime('now'));
    

    输出为:

    Elapsed time is 35.192704 seconds.
       15-Sep-2018 16:51:35
    

    使用以下最小工作示例从C中计时MEX文件:

    #include <mex.h>
    #include <sys/time.h>
    #include <time.h>
    #include <cuComplex.h>
    
    double getHighResolutionTime() {
        struct timeval tod;
        gettimeofday(&tod, NULL);
        double time_seconds = (double) tod.tv_sec + ((double) tod.tv_usec / 1000000.0);
        return time_seconds;
    }
    
    void double2cuDoubleComplex(cuDoubleComplex* p, double* pr, double* pi,int numElements){
        for(int j=0;j<numElements;j++){
            p[j].x=pr[j];
            p[j].y=pi[j];
        }
    }
    
    void cuDoubleComplex2double(cuDoubleComplex* p, double* pr, double* pi,int numElements){
        for(int j=0;j<numElements;j++){
            pr[j]= p[j].x;
            pi[j]= p[j].y;
        }
    }
    
    void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[]) {
    
        double tic=getHighResolutionTime();
    
        int m=(int)mxGetM(prhs[0]);
        int n=(int)mxGetN(prhs[0]);
        int SIZE=m*n;
    
        //get pointers to input data from matlab and convert to 
        //interleaved (Fortran) ordering
        cuDoubleComplex *Gr= (cuDoubleComplex*) mxMalloc(SIZE*sizeof(cuDoubleComplex));
        double2cuDoubleComplex(Gr,mxGetPr(prhs[0]),mxGetPi(prhs[0]),SIZE);
    
    
        //modify the input data, allocate output matrices, and convert 
        //back to split (matlab) ordering.
        Gr[0].x=0.0;
        plhs[0] = mxCreateDoubleMatrix(m,m,mxCOMPLEX);
        cuDoubleComplex2double(Gr,mxGetPr(plhs[0]),mxGetPi(plhs[0]),SIZE);
    
        Gr[0].x=1.0;
        plhs[1] = mxCreateDoubleMatrix(m,m,mxCOMPLEX);
        cuDoubleComplex2double(Gr,mxGetPr(plhs[1]),mxGetPi(plhs[1]),SIZE);
    
        Gr[0].x=2.0;
        plhs[2] = mxCreateDoubleMatrix(m,m,mxCOMPLEX);
        cuDoubleComplex2double(Gr,mxGetPr(plhs[2]),mxGetPi(plhs[2]),SIZE);
    
        mxFree(Gr);
    
        double elapsed=getHighResolutionTime()-tic;mexPrintf("%f\n", elapsed);
        time_t current_time = time(NULL);
        char* c_time_string = ctime(&current_time);
        mexPrintf("time at end of MEX file %s\n", c_time_string);
    }
    

    输出为:

    21.676793
    time at end of MEX file Sat Sep 15 16:51:21 2018
    

    输出是非常大的矩阵,但是它们在MEX文件的最后一行之前被成功地分配和初始化。我想不出别的了。是什么导致了这种行为?我该如何避免这种行为?

    更新:我已经用一个最小的工作示例替换了上面的伪代码。请注意,上面的代码实际上并不使用任何GPU功能。我加入cuComplex.h头只是为了使用cuDoubleComplex数据类型。

    1 回复  |  直到 7 年前
        1
  •  5
  •   Cris Luengo    7 年前

    从MATLAB R2018a开始, MATLAB internally stores complex arrays in an interleaved format . 在以前的版本中,MATLAB使用两个独立的内存块来存储复杂的数据:一个用于实值,另一个用于虚值。在MEX文件中,您使用 mxGetPr() mxGetPi() 获取指向这两个内存块的指针(这些函数称为“单独的复杂API”)。

    从R2018a开始,使用新的内部数据表示法,可以用两种不同的方式编译MEX文件:

    1. 兼容模式(这是默认模式,您可以添加 -R2017b mex

    2. 新模式(添加 -R2018a 命令),MEX文件使用 the new "Interleaved Complex API"

    避免处理复杂数组的MEX文件在开始和结束时出现大延迟的解决方案是重写它们以使用新的“交错复杂API”。这需要 the following changes

    • 找到 mxGetPr() mxGetPi() 功能。后者不再可用。 mxGetPr() 如果输入数组是复数的,则抛出一个错误。相反,使用 mxGetData() ,它将返回指向复杂交错数据的指针。请注意,他们建议您不要将其用于数字数据,似乎 they prefer you use the new "typed data access functions" . mxGetImagData() ,就像 mxGetPi()

    • 设置数据指针的函数也是如此( mxSet...() ).

    • 别忘了检查输入数组是否真的很复杂并且是double类型,使用 mxIsComplex() mxIsDouble()

    • 函数 mxGetElementSize 现在对于复杂的双精度数据返回16,而不是以前的8。

    • 使用编译MEX文件 mex -R2018a <filename>

    Here are some more troubleshooting tips