Почему возвращение в Matlab после достижения последней строки MEX-файла занимает так много времени? - PullRequest
0 голосов
/ 15 сентября 2018

Для возврата к командной строке matlab после выполнения последней строки моего MEX-файла требуется приблизительно ~ 14 секунд.

При синхронизации файла MEX из matlab:

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

При синхронизации файла MEX изнутри C, используя следующий минимальный рабочий пример:

#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

Matlab возвращает время 35,19 с, в то время как MEX-файлу на самом деле требуется 21,67 с, чтобы достичь последней строки. Дата и время находятся на расстоянии ~ 14 секунд, то есть 16:51:21 для файла MEX и 16:51:35 для matlab.

Выходные данные являются очень большими матрицами, но они успешно размещены и инициализированы перед последней строкой файла MEX. Я не могу думать ни о чем другом. Что вызывает это поведение и как мне его избежать?

Обновление: я пробовал это на большем количестве машин, и расхождение во времени все еще там.

Обновление: я заменил приведенный выше псевдокод на минимальный рабочий пример. Обратите внимание, что код, приведенный выше, на самом деле не использует никаких функций графического процессора Я включаю заголовок cuComplex.h только для использования типа данных cuDoubleComplex.

1 Ответ

0 голосов
/ 16 сентября 2018

Начиная с MATLAB R2018a, MATLAB внутренне хранит сложные массивы в чередующемся формате . В предыдущих версиях MATLAB использовала два отдельных блока памяти для хранения сложных данных: один для реальных значений и один для мнимых значений. В MEX-файле вы использовали mxGetPr() и mxGetPi() для получения указателей на эти два блока памяти (эти функции называются «Отдельный сложный API»).

Начиная с R2018a, с новым внутренним представлением данных, MEX-файлы могут быть скомпилированы двумя различными способами:

  1. Режим совместимости (это значение по умолчанию, вы можете добавить -R2017b к команде mex, чтобы включить этот режим), где вы можете скомпилировать старые MEX-файлы без изменений. Эти MEX-файлы, таким образом, используют «Отдельный комплексный API». MATLAB копирует сложные данные из своего нового чередованного представления в отдельные блоки реальной и мнимой памяти перед выполнением кода MEX-файла и копирует все сложные выходные массивы обратно в чередующийся формат. Это, очевидно, стоит времени. Это является причиной задержки, наблюдаемой OP.

  2. Новый режим (добавьте -R2018a к команде mex), в котором MEX-файлы используют новый "Interleaved Complex API" . То есть код MEX-файла адаптирован для использования нового чередующегося сложного формата. Поскольку большинство библиотек C и C ++, которые вы, возможно, захотите вызывать из своего MEX-файла, используют чередующийся формат, это на самом деле большое преимущество.

Решение, позволяющее избежать большой задержки в начале и конце MEX-файлов, обрабатывающих сложные массивы, состоит в том, чтобы переписать их для использования нового «Interleaved Complex API». Это требует следующих изменений :

  • Найдите все варианты использования функций mxGetPr() и mxGetPi(). Последний больше не доступен. mxGetPr() теперь выдает ошибку, если входной массив имеет комплексное значение. Вместо этого используйте mxGetData(), который вернет указатель на сложные чередующиеся данные. Обратите внимание, что они рекомендуют не использовать его для числовых данных, кажется, они предпочитают использовать новые "типизированные функции доступа к данным" . mxGetImagData(), как и mxGetPi(), больше не существует.

  • То же самое верно для функций, которые устанавливают указатель данных (mxSet...()).

  • Не забудьте проверить, является ли входной массив сложным и имеет тип double, используя mxIsComplex() и mxIsDouble().

  • Функция mxGetElementSize теперь возвращает 16 для сложных двойных данных, а не 8, как раньше.

  • Скомпилируйте ваш MEX-файл, используя mex -R2018a <filename>.

Вот еще несколько советов по устранению неполадок .

...