How Do I use Mexcallmatlab to Call a User-defined function?
Show older comments
I am trying to parallelize a section of my Matlab code using OpenMP in a mex file. The section in theMatlab code that I want to parallelize is:
for i = 1 : n
D(:, i) = CALC(A, B(:,i), C(i));
end
I have written this in order to parallelize it:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
size_t r,n,i,G;
double *A, *B, *C, *D;
int nthreads;
nthreads = 4;
A = mxGetPr(prhs[0]); /* first input matrix */
B = mxGetPr(prhs[1]); /* second input matrix */
C = mxGetPr(prhs[2]);/* third input matrix */
/* dimensions of input matrices */
r = mxGetN(prhs[0]);
n = mxGetN(prhs[1]);
plhs[0] = mxCreateDoubleMatrix(r,n, mxREAL);
D = mxGetPr(plhs[0]);
G=n/nthreads;
omp_set_num_threads(nthreads);
#pragma omp parallel for schedule (dynamic, G)
{
for i = 1 : n
D(:, i) = CALC(A, B(:,i), C(i));
}
}
CALC is a Matlab function I have written. My challenge is how to use Mexcallmatlab to call in the CALC function to the mex file so that it can execute it in parallel inside my mex file, and return the elements of each column of D (i.e. D(:, i) back to my Matlab code.
Sorry for the lenghty question. Any help I can get on this will be highly appreciated.
Accepted Answer
More Answers (2)
Philip Borghesani
on 12 Jun 2015
Edited: Philip Borghesani
on 12 Jun 2015
0 votes
This will not work. MATLAB and mexCallMatlab are not thread safe, there is no way to call a MATLAB function from an OpenMP for loop and expect proper operation. I suggest investigating the parfor MATLAB loop.
Arwel
on 2 Apr 2021
One way I have done this in the past is rather than trying to call back into the origonal Matlab workspace, instead to launch seperate matlab engine sessions for each thread in the loop and use them instead. They seem to stay separate ok (but I havent tested that to destruction!)
So, within the OMP loop, instead call a function such as the one below. This is from an old example I used and the inputs will differ for yours, but it starts a Matlab engine, and then excecutes a function named in the string myFun using 'eval'. In this case the function has four inputs and two outputs - you just need to put them as correct variable names into the engine workspace first.
When you put this in the OMP loop, what happens is that multiple engines open, and it seemed to me to work correctly with no clashes between instances. I had expected to need to do more work to get that, but it just seemed to do it okay. So for four cores, 4 sessions open and so on. They are slow to start on the first pass through, but then seem to stay open until destroyed.
It should be possible to adapt something for this for your purposes, by just making the 'evalstring' what you need. ( Caveat: I haven't tried this in a while, but from memory worked okay!)
Cheers,
Arwel
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
void matlabCallFun(double params[], int arrayLen, char *funName, char *pathCall, double bulkIn, double bulkOut, double contrast, double *sum, double *ans)
{
static Engine *ep;
static double engStatus = 0;
mxArray *result = NULL;
mxArray *PARAMS = NULL;
mxArray *BULKIN = NULL;
mxArray *BULKOUT = NULL;
mxArray *CONTRAST = NULL;
mxArray *lays = NULL;
double* s;
double* layers;
/*Contrast = -1 means start engine only, then return*/
if(contrast == -1) {
ep = engOpen("");
if(ep==0) {
printf("Connecton to Matlab Engine failed\n");
return;
}
else {
printf("Starting Matlab Engine\n");
engStatus == 1;
return;
}
}
/*Contrast = -2 means close engine only (if open), then return*/
if(contrast == -2) {
if(ep==0) {
printf("No engine open\n");
}
else {
printf("Closing Matlab Engine\n");
engClose(ep);
engStatus == 0;
return;
}
}
/*Automatically start engine if closed to catch non-initialised call*/
if(engStatus == 0) {
ep = engOpen("");
if(ep==0) {
printf("Connecton to Matlab Engine failed\n");
return;
}
else {
printf("Starting Matlab Engine\n");
mxArray* MYPATH = mxCreateString(pathCall);
engPutVariable(ep, "mypath", MYPATH);
engEvalString(ep,"eval(mypath)");
mxDestroyArray(MYPATH);
engStatus = 1;
}
}
PARAMS = mxCreateDoubleMatrix(1,arrayLen,mxREAL);
memcpy(mxGetPr(PARAMS), params, arrayLen*sizeof(double));
engPutVariable(ep,"params",PARAMS);
BULKIN = mxCreateDoubleMatrix(1,1,mxREAL);
memcpy((void *)mxGetPr(BULKIN), &bulkIn, 1*sizeof(double));
engPutVariable(ep,"bulk_in",BULKIN);
BULKOUT = mxCreateDoubleMatrix(1,1,mxREAL);
memcpy((void *)mxGetPr(BULKOUT), &bulkOut, 1*sizeof(double));
engPutVariable(ep,"bulk_out",BULKOUT);
CONTRAST = mxCreateDoubleMatrix(1,1,mxREAL);
memcpy((void *)mxGetPr(CONTRAST), &contrast, 1*sizeof(double));
engPutVariable(ep,"contrast",CONTRAST);
mxArray* MYFUN = mxCreateString(funName);
engPutVariable(ep, "myfun", MYFUN);
engEvalString(ep,"eval(myfun)");
/*Or a full sting instead of eval e.g. */
/*engEvalString(ep,"[total,layers] = debugMfile(params,bulk_in,bulk_out,contrast)");*/
mxDestroyArray(MYFUN);
result = engGetVariable(ep,"total");
s = (double *)mxGetData(result);
memcpy( sum, s, mxGetNumberOfElements(result)*sizeof(double) );
lays = engGetVariable(ep,"layers");
layers = (double *)mxGetData(lays);
memcpy(ans,layers,mxGetNumberOfElements(lays)*sizeof(double) );
/*engClose(ep)*/;
mxDestroyArray(PARAMS);
mxDestroyArray(BULKIN);
mxDestroyArray(BULKOUT);
mxDestroyArray(CONTRAST);
};
Categories
Find more on Parallel Computing Toolbox in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!