Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matlab Mex library lifecycle

Tags:

c++

c

matlab

mex

Does anyone know what the matlab mex library lifecycle is? Specifically I am interested in the following:

  1. Is there a way to force the library to be loaded before invoking it?
  2. Is the library a singleton or are multiple instances loaded?
  3. Are there any hooks for initialization prior to invocation?
  4. Is there a destructor hook/signal that can be intercepted when the library is unloaded for cleanup?

I did an extensive search here and online and I could not find the answers to these questions. My problem has some performance cost with initialization and I would like to avoid that if possible, without needing to write a service.

like image 853
panos Avatar asked Dec 13 '13 21:12

panos


People also ask

How does MEX work MATLAB?

A MEX file is a function, created in MATLAB, that calls a C/C++ program or a Fortran subroutine. A MEX function behaves just like a MATLAB script or function. To experiment with calling MEX functions, use the code in Tables of MEX Function Source Code Examples to build and run examples.

How do I debug a MEX file in MATLAB?

To debug your MEX functions, use the disp function to inspect the contents of your MEX function variables. You cannot use save to debug MEX function variables because code generation does not support it. Code generation does not support declaration of save as extrinsic.

How do I load a MEX file into MATLAB?

To call a MEX file, put the file on your MATLAB® path. Then type the name of the file, without the file extension. If you have MEX file source code, see Build C MEX Function for information about creating the executable function.

What is MEX compiler?

mex filenames compiles and links one or more C++ source files written with the MATLAB Data API for C++ into a binary MEX file in the current folder. For information about writing these applications, see Write C++ Functions Callable from MATLAB (MEX Files).


2 Answers

A MEX file stays loaded until you clear it (clear myMexFun or clear mex) or quit MATLAB.

For pre-loading, all I can suggest is to call the function with no inputs or with nop-equivalent inputs. I have created simple code paths in my mexFunctions to handle such calls without error, the simplest example being if(!nrhs) return;. Subsequent calls will not need to load the mexFunction from disk (or any other functions in shared libraries called by the MEX function) and you do not need to worry about initialization cost after that.

Regarding initialization/cleanup, constructors/destructors, etc. I am not aware of any way to see what MATLAB is doing when loading or unloading the MEX file, but a MEX file is a regular shared library (i.e. DLL/SO) that just exports a single function (mexFunction is the only entry point), so, as Amro points out, you can implement a DllMain in Windows to define module and thread attach/detach operations (see the excellent example in his answer). I'm not aware of any other mechanisms for interacting with the library.

To perform tasks when the module unloads, you can use mexAtExit within mexFunction to register with MATLAB a function to call when the MEX function unloads (again, cleared or MATLAB exits). Simply define a static function in the global namespace and register it with mexAtExit. The example provided by MATLAB (mexatexit.c) demonstrates closing a file stream that was opened within mexFunction, but not closed. You could also free persistent memory, close streams, etc. Here is a contrived example:

mexDLLtext.cpp:

#include "mex.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

static FILE   *fp=NULL;
static double *pDataC=NULL, *pDataCpp=NULL, *pMxData=NULL;
static char fName[L_tmpnam], counter = 0;

static void CleanUp(void)
{
  fclose(fp);        /* close file opened with fopen */
  free(pDataC);      /* deallocate buffer allocated with malloc/calloc */
  delete[] pDataCpp; /* deallocate buffer allocated with new double[...] */
  mxFree(pMxData);   /* free data created with mx function like mxMalloc */

  mexPrintf("Closing %s and freeing memory...\n",fName);
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    if (!fp) { tmpnam(fName); fp = fopen(fName,"w"); }
    fprintf(fp,"%d ",++counter);

    if (!pDataC) pDataC = (double*) malloc(sizeof(double)*16);
    if (!pDataCpp) pDataCpp = new double[16];
    if (!pMxData) {
        pMxData = (double*) mxMalloc(sizeof(double)*16);
        mexMakeMemoryPersistent(pMxData); mexPrintf("First!\n");
    }

    mexAtExit(CleanUp);
    // Then use the persistent data...
}

When run:

>> mex -largeArrayDims mexDLLtest.cpp
>> for i=1:5, mexDLLtest; end
First!
>> clear mexDLLtest
Closing \s1rg.1 and freeing memory...
>> type E:\s1rg.1

1 2 3 4 5 

And you have some control over unloading of the file via mexLock and mexUnlock.

What happens to the arguments (i.e. prhs, plhs) when the function starts and returns to MATLAB is very well documented, on the other hand, so I guess that's not what you are asking about.

Regarding multiple instances, you could try using Sysinternals' Process Explorer (if using Window) to have a look at what loaded modules have threads running under MATLAB.exe. I only ever see one instance of a (single threaded) MEX file in threads list no matter how many times or how fast I call the function. However, once back at the command line, you can do version -modules to see a list of loaded modules, as Amro suggested. The MEX file will still be there, and as with the list of threads visible by Process Explorer, I only ever see one instance of a MEX certain file.

Thanks, Amro for the input. I'm interested to see even some more authoritative answers to these questions!

like image 128
chappjc Avatar answered Oct 20 '22 04:10

chappjc


As I mentioned in the comments, in Windows you could implement DllMain entry point. This is because MEX-file are just regular DLL files with different extension. Here is a minimal example:

testDLL.cpp

#include "mex.h"
#include <windows.h>

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
    switch (dwReason) {
    case DLL_PROCESS_ATTACH:
        mexPrintf("DLL_PROCESS_ATTACH: hModule=0x%x\n", hModule);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        mexPrintf("DLL_PROCESS_DETACH: hModule=0x%x\n", hModule);
        break;
    }
    return TRUE;
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    mexPrintf("Inside MEX-function\n");
}

Here is how it works:

>> mex -largeArrayDims testDLL.cpp

>> testDLL
DLL_PROCESS_ATTACH: hModule=0xa0980000
Inside MEX-function

>> testDLL
Inside MEX-function

>> clear testDLL
DLL_PROCESS_DETACH: hModule=0xa0980000
like image 22
Amro Avatar answered Oct 20 '22 06:10

Amro