Передача большой матрицы из Matlab в C с использованием mex: сбой Matlab

Я написал код mex, который отправляет скаляр и матрицу в C-код из кода Matlab. Он отлично работает с меньшей матрицей. Однако, когда я пытаюсь передать большую разреженную матрицу (размер ~ 8448 x 3264), Matlab вылетает со следующей ошибкой:

Я получаю следующую ошибку: Matlab обнаружил внутреннюю проблему и должен быть закрыт.

                  *Detailed error report*


------------------------------------------------------------------------
         Segmentation violation detected at Mon Feb  9 13:21:48 2015
  ------------------------------------------------------------------------

  Configuration:
    Crash Decoding     : Disabled
    Current Visual     : None
    Default Encoding   : UTF-8
    GNU C Library      : 2.19 stable
    MATLAB Architecture: glnxa64
    MATLAB Root        : /usr/local/MATLAB/R2014b
    MATLAB Version     : 8.4.0.150421 (R2014b)
    Operating System   : Linux 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64
    Processor ID       : x86 Family 6 Model 44 Stepping 2, GenuineIntel
    Software OpenGL    : 1
    Virtual Machine    : Java 1.7.0_11-b21 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
    Window System      : No active display

  Fault Count: 1


  Abnormal termination:
  Segmentation violation

  Register State (from fault):
    RAX = 00007f011f000000  RBX = 0000000000000001
    RCX = 0000000000260fe0  RDX = 00007f0162197000
    RSP = 00007f024fffb4f0  RBP = 00007f024fffb4f0
    RSI = 00007f011ed9f020  RDI = 00007f0161f36020

     R8 = 00007f011ed9f010   R9 = 0000000000000000
    R10 = 0000000000000022  R11 = 0000000048000001
    R12 = 00007f024fffbaf0  R13 = 00007f01c63b57f0
    R14 = 00007f024fffbb00  R15 = 00007f024fffbb00

    RIP = 00007f01618d491e  EFL = 0000000000010206

     CS = 0033   FS = 0000   GS = 0000

  Stack Trace (from fault):
  [  0] 0x00007f01618d491e /home/dkumar/Mex_Codes_DKU/Matlab_Calling_C/Test_2/mexcallingmatlab.mexa64+00002334
  [  1] 0x00007f01618d4a8e /home/dkumar/Mex_Codes_DKU/Matlab_Calling_C/Test_2/mexcallingmatlab.mexa64+00002702 mexFunction+00000325
  [  2] 0x00007f025ef7ac0a     /usr/local/MATLAB/R2014b/bin/glnxa64/libmex.so+00150538 mexRunMexFile+00000090
  [  3] 0x00007f025ef775c4     /usr/local/MATLAB/R2014b/bin/glnxa64/libmex.so+00136644
  [  4] 0x00007f025ef78414     /usr/local/MATLAB/R2014b/bin/glnxa64/libmex.so+00140308
  [  5] 0x00007f025e2af329 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_dispatcher.so+00791337 _ZN8Mfh_file11dispatch_fhEiPP11mxArray_tagiS2_+00000697
  [  6] 0x00007f025d189b70 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+04053872
  [  7] 0x00007f025d139e02 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03726850
  [  8] 0x00007f025d13c022 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03735586
  [  9] 0x00007f025d141f87 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03760007
  [ 10] 0x00007f025d13d6ff /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03741439
  [ 11] 0x00007f025d13e334 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03744564
  [ 12] 0x00007f025d1b352e /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+04224302
  [ 13] 0x00007f025e2af329 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_dispatcher.so+00791337 _ZN8Mfh_file11dispatch_fhEiPP11mxArray_tagiS2_+00000697
  [ 14] 0x00007f025d189b70 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+04053872
  [ 15] 0x00007f025d10a293 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03531411
  [ 16] 0x00007f025d13b0de /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03731678
  [ 17] 0x00007f025d141f87 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03760007
  [ 18] 0x00007f025d13d6ff /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03741439
  [ 19] 0x00007f025d13e334 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03744564
  [ 20] 0x00007f025d1b352e /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+04224302
  [ 21] 0x00007f025e2af4af /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_dispatcher.so+00791727 _ZN8Mfh_file11dispatch_fhEiPP11mxArray_tagiS2_+00001087
  [ 22] 0x00007f025d171ff5 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03956725
  [ 23] 0x00007f025d133699 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03700377
  [ 24] 0x00007f025d12fa87 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03684999
  [ 25] 0x00007f025d130143 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwm_interpreter.so+03686723
  [ 26] 0x00007f025f1bb9dc /usr/local/MATLAB/R2014b/bin/glnxa64/libmwbridge.so+00223708
  [ 27] 0x00007f025f1bc649 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwbridge.so+00226889 _Z8mnParserv+00000729
  [ 28] 0x00007f02698c6b7f   /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00772991 _ZN11mcrInstance30mnParser_on_interpreter_threadEv+00000031
  [ 29] 0x00007f02698a7083   /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00643203
  [ 30] 0x00007f02698a8d69   /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00650601 _ZN5boost6detail11task_objectIvNS
  #include "mex.h"

  void xtimesy(double x, double *y, double *z, int m, int n)
  {
    int i,j,count = 0;

    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            *(z+count) = x * *(y+count);
            count++;
        }
    }
  }


  void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  {
    double *y, *z;
    double x;
    int status,mrows,ncols;


    if (nrhs != 2) 
        mexErrMsgTxt("Two inputs required.");
    if (nlhs != 1) 
        mexErrMsgTxt("One output required.");

    /* Check to make sure the first input argument is a scalar. */
    if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) ||
        mxGetN(prhs[0])*mxGetM(prhs[0]) != 1) {
        mexErrMsgTxt("Input x must be a scalar.");
    }

    /* Get the scalar input x. */
    x = mxGetScalar(prhs[0]);

    /* Create a pointer to the input matrix y. */
    y = mxGetPr(prhs[1]);

    /* Get the dimensions of the matrix input y. */
    mrows = mxGetM(prhs[1]);
    ncols = mxGetN(prhs[1]);

    /* Set the output pointer to the output matrix. */
    plhs[0] = mxCreateDoubleMatrix(mrows,ncols, mxREAL);

    /* Create a C pointer to a copy of the output matrix. */
    z = mxGetPr(plhs[0]); 

    /* Call the C subroutine. */
    xtimesy(x, y, z, mrows, ncols);    // Passing x as a scalar and y,z as pointer; possibly implicit converion of y,z to their pointers

  }
bi6bind_tIvPFvRKNS_8functionIFvvEEEENS2_5list1INS2_5valueIS6_EEEEEEE6do_runEv+00000025 [ 31] 0x00007f02698a9737 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00653111 _ZN5boost6detail9task_baseIvE3runEv+00000071 [ 32] 0x00007f02698a9797 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00653207 [ 33] 0x00007f02698a4bca /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00633802 [ 34] 0x00007f025c4eaa46 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwuix.so+00330310 [ 35] 0x00007f025c4d2ad2 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwuix.so+00232146 [ 36] 0x00007f026a06700f /usr/local/MATLAB/R2014b/bin/glnxa64/libmwservices.so+02523151 [ 37] 0x00007f026a06717c /usr/local/MATLAB/R2014b/bin/glnxa64/libmwservices.so+02523516 [ 38] 0x00007f026a06307f /usr/local/MATLAB/R2014b/bin/glnxa64/libmwservices.so+02506879 [ 39] 0x00007f026a0684b5 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwservices.so+02528437 [ 40] 0x00007f026a0688e7 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwservices.so+02529511 [ 41] 0x00007f026a068fc0 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwservices.so+02531264 _Z25svWS_ProcessPendingEventsiib+00000080 [ 42] 0x00007f02698a5248 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00635464 [ 43] 0x00007f02698a5564 /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00636260 [ 44] 0x00007f0269891cdd /usr/local/MATLAB/R2014b/bin/glnxa64/libmwmcr.so+00556253 [ 45] 0x00007f026877b182 /lib/x86_64-linux-gnu/libpthread.so.0+00033154 [ 46] 0x00007f02684a7fbd /lib/x86_64-linux-gnu/libc.so.6+01028029 clone+00000109 This error was detected while a MEX-file was running. If the MEX-file is not an official MathWorks function, please examine its source code for errors. Please consult the External Interfaces Guide for information on debugging MEX-files.

Вот мой код Matlab:

% Create system matrix (size 8448 x 3264)
smA_System = ConstructSystemMatrix();

    x = 9;
    y = ones(3);

    % This works fine
    z = mexcallingmatlab(x, y);

    % This gives error
    z = mexcallingmatlab(x, smA_System);

Вот мой mex-код

  #include "mex.h"

  void xtimesy(double x, double *y, double *z, int m, int n)
  {
    int i,j,count = 0;

    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            *(z+count) = x * *(y+count);
            count++;
        }
    }
  }


  void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  {
    double *y, *z;
    double x;
    int status,mrows,ncols;


    if (nrhs != 2) 
        mexErrMsgTxt("Two inputs required.");
    if (nlhs != 1) 
        mexErrMsgTxt("One output required.");

    /* Check to make sure the first input argument is a scalar. */
    if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) ||
        mxGetN(prhs[0])*mxGetM(prhs[0]) != 1) {
        mexErrMsgTxt("Input x must be a scalar.");
    }

    /* Get the scalar input x. */
    x = mxGetScalar(prhs[0]);

    /* Create a pointer to the input matrix y. */
    y = mxGetPr(prhs[1]);

    /* Get the dimensions of the matrix input y. */
    mrows = mxGetM(prhs[1]);
    ncols = mxGetN(prhs[1]);

    /* Set the output pointer to the output matrix. */
    plhs[0] = mxCreateDoubleMatrix(mrows,ncols, mxREAL);

    /* Create a C pointer to a copy of the output matrix. */
    z = mxGetPr(plhs[0]); 

    /* Call the C subroutine. */
    xtimesy(x, y, z, mrows, ncols);    // Passing x as a scalar and y,z as pointer; possibly implicit converion of y,z to their pointers

  }

Обновление: спасибо, Шай, что указал на мою ошибку. Буду признателен, если вы ответите на еще один вопрос. Как лучше всего передать разреженную матрицу? 1) Передав указатель на матрицу, как я это делаю в своем mex-файле 2) Передав указатель на ненулевые элементы следующим образом:

[rows cols values] = find(smA_System);
[nrows ncols] = size(smA_System);

а затем передать указатель на строки, столбцы, значения.


person Garima Singh    schedule 09.02.2015    source источник


Ответы (1)


Как вы указали в своем вопросе, ваш код подходит только для чтения матриц full в качестве второго аргумента. Когда prhs[1] является разреженной матрицей, вы больше не можете получить к ней доступ как к полной матрице, используя *(y+count): она РАЗДЕЛЬНАЯ, она не занимает n всего в памяти, но гораздо меньше.
Для доступа к элементам разреженной матрицы в mex следует использовать mxGetIr и mxGetJc. Способ, которым Matlab хранит разреженную матрицу, лучше всего объясняется здесь.
Более того, ваша входная матрица разрежена, а выходная матрица заполнена — это может вызвать ошибку нехватки памяти при попытке выделить выходную матрицу. Тем не менее, вы не проверяете plhs[0], возвращенное из mxCreateDoubleMatrix(mrows,ncols, mxREAL);, скорее всего, это NULL.

Обновлять:

Лучше всего передавать разреженную матрицу в ваш код mex как есть.
В вашей функции mex вы должны:

  1. Убедитесь, что входные данные действительно разрежены, как и ожидалось. См. mxIsSparse.
  2. Получите три соответствующих указателя (четыре для комплексных матриц), используя mxGetIr, mxGetJc и mxGetPr.
  3. Работайте с ir и jc напрямую, а не с парами строк-столбцов, которые менее компактны.
person Shai    schedule 09.02.2015
comment
Спасибо. У меня есть дополнительный вопрос о передаче разреженной матрицы с использованием mex. Пожалуйста, смотрите обновленную часть моего вопроса. Буду признателен, если вы ответите и на это. - person Garima Singh; 09.02.2015
comment
@GarimaSingh Вероятно, вам следует задать новый вопрос, а не менять свой вопрос. - person chappjc; 09.02.2015
comment
Если mxCreateDoubleMatrix выходит из памяти при попытке выделения, он просто завершается. MEX-файл и возвращает управление MATLAB, поэтому, к сожалению, у вас не будет возможности проверить NULL @GarimaSingh Прежде чем публиковать продолжение, приложите все усилия с разреженными вспомогательными функциями. - person chappjc; 09.02.2015
comment
@chappjc, возможно, ты прав. Я не припомню, чтобы когда-нибудь получалось сообщение об отсутствии памяти в mex-файле... - person Shai; 09.02.2015