Can anyone give me any help on how to get a variable defined in the first mexFunction and then used in the second mexFunction (like a pointer to some address in a memory for example).
Thanks!
Make the variable a return value of the first mexFunction and an input
value to the second.
Return the variable to the MATLAB workspace and then pass that into the 2nd mexFunction. Do you need something fancier? Does the 2nd mexFunction need to then pass it back to the 1st mexFunction again?
James Tursa
Can base ML receive and send pointers??
You may need to have both MEX functions depend on another lib that's used for storing and passing pointers.
No the second mexfunction will just get back result to the main function. All I need is to get a pointer to an address from the first function to the second.
Does it have to be a pointer to the result? Can't you just have the
result passed by value? As Steve mentioned earlier mex functions
probably cannot pass around pointers and you may have to resort to
some other method to achieve this.
HTH,
Ashish.
I am working on a project that is using mexFunction to do a computations on a graphic card (CUDA). In a first mexFunction I would like to read the input matrix from Matlab onto the graphic card memory (I already done that). As an output of this first mexFunction I would need to get an address to the location on this matrix in the graphic card memory. That info will be needed in the second mexFunction that will be doing the matrix multiplication between the first matrix that is already in the memory and the second matrix that will be different for every run of the second mexFunction.
I am still not sure I completely understand your problem. However, here are a couple of mex files that may serve as an outline that will get the job done for you.
The first mex file allocates some memory for a top level variable, k, that stays in memory after the mex file exits (as long as you don't clear the function). The address of this memory is put into a MATLAB uint32 class variable (assumes addresses are 4-bytes long). This is passed back to the MATLAB workspace as the 1st and only output.
The second mex file gets passed the uint32 class variable as input, extracts the address from the data area, and then interprets this as the address of the original array and prints it out. You can see that it sees the same memory.
This is *not* a complete example of how to do this safely with just C top level variables because clearing the first mex function will make the memory invalid and will mess up the second function. However, since your memory is on a graphics card and in effect "permanent" if I understand the situation, this will not be a problem for you. As long as you don't clear the MATLAB uint32 variable that contains the address then you will always have a handle to the graphics card memory that you can get at with another mex function.
James Tursa
------------------------------------------------------
mexfile1.c
#include "mex.h"
int k[11] = {-5,-4,-3,-2,-1,0,1,2,3,4,5};
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int **kpp;
plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT32_CLASS, mxREAL);
kpp = mxGetData(plhs[0]);
*kpp = &k;
}
------------------------------------------------------
mexfile2.c
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int i;
int *kp;
kp = *((int **)mxGetData(prhs[0]));
for( i=0; i<11; i++ )
mexPrintf("k[%d] = %d\n",i,kp[i]);
}
------------------------------------------------------
>> mex mexfile1.c
>> mex mexfile2.c
>> kaddress = mexfile1
kaddress =
252129340
>> mexfile2(kaddress)
k[0] = -5
k[1] = -4
k[2] = -3
k[3] = -2
k[4] = -1
k[5] = 0
k[6] = 1
k[7] = 2
k[8] = 3
k[9] = 4
k[10] = 5
>>
Danger!
Assuming that addresses will happily be carried around as other data types is the kind of bug that sinks ships, downs planes, loses spacecraft, etc. Don't do it! You might get lucky for a while on one platform with one compiler. But ultimately it'll break - big time.
There is a huge amount of code out there that's only been working all this time because ints and addresses have both been 4 bytes wide for quite a while.
As this is only a diploma assignment that will be run on one platform only the important bit is to prove a concept not reliability so first I just need to get it to work, reliability will be needed later, or maybe never for this program :)
James Tursa: Thanks for your code I will try to make it work today and will get back with the results.
David,
If I understand your problem correctly then it seems to me like you're
looking for the wrong solution here. Why do you need a direct pointer
to the data in the graphic card memory? You should be able to access
the data from the second mex file if you know the memory location and
length of the data. For instance, let's say the memory address range
on the graphics card is 0x0000 - 0xFFFF and that you've filled the
entire bottom half with data from the Matlab matrix (first mex file).
Then, if this file simply returns 0x0000 (start address) and 0x7FFF
(length), the second mex file should be able to access the data from
the graphics card memory.
Ashish.
I am able to access the data on the graphic card from the second mex file, that is not the problem. But the data on the graphic card is not saved on the same address all the time. So I need to get an address to where it is allocated in a second mex file.
Hmm,
If your graphics card is memory mapped (which I'm sure it is), then
what I've said and James' solution are one and the same isn't it?
Sorry, I come from the embedded device world where peripherals are not
always memory mapped. Also, posting at 3 AM might have something to do
with it :-)
Ashish.
Of course. That is why I pointed out this assumption in my post. If OP wants more portability then sizeof checks can be done at run time and appropriate storage allocated.
James Tursa
Why create time bombs when the safe alternative is simpler:
(Not tested).
/******************************/
/* Compile/link me into a DLL */
static double *pval=NULL;
double *getPointer(void)
{
return pval;
}
void storePointer(double *p)
{
pval=p;
}
/***************************/
No reason. Like I said in my first post, the code was just an outline, not complete, and not safe as is. It could be made safe with some code to do sizeof checks etc. The only advantage to this approach, I suppose, is you don't have to build an extra dll and get it loaded etc.
That being said, I agree with you that building a dll to just contain the pointer (and maybe other stuff) would seem to be simpler for OP's application. OP would need to learn how to do the build.
In either case there would have to be extra code (not shown in my toy example or yours) to check validity of the pointer value, etc.
James Tursa
Could please someone explain me a little more about making a DLL library that I could use for my problem?
I tried using the first method described here and I was able to transfer the matrix to the GPU memory, keep it there and get the address of the matrix returned to matlab as variable. But I was not able to use thet pointer in the second function because I was not able to get the right value of the matrix address into the second function through mexFunction that accepts only mxArray types.
So now I would like to try the second option with DLL but as I don't have any experience with such technique I would kindly ask you to explain it to me a little more in detail.
Thanks and best regards,
David
Can you post the code that you used to try this method? I don't see why it wouldn't work using the scheme I posted earlier. Basically allocate enough space in an mxArray to hold your pointer, put the pointer into the mxArray, and extract the pointer value at the other end.
James Tursa
The first function that is called from matlab like this [kazalecGPU]=stalnaMatrikaGPU(MatrikaA);:
#include "mex.h"
#include "cuda.h"
static int initialized = 0;
static int *SkazalecGPU;
void cleanup(void) {
mexPrintf("MEX-file se zakljucuje unici polje\n");
cudaFree(SkazalecGPU);
mexPrintf("CUDA polje se je sprostilo.\n");
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
float *kazalecHost;
int i;
//stolpecA in vrsticaB morata biti iste velikosti
int vrsticaA = mxGetM(prhs[0]); /* preberemo stevilo vrstic A */
int stolpecA = mxGetN(prhs[0]); /* preberemo stevilo stolpcev A */
mexPrintf("\nThere are %d right-hand-side argument(s).", nrhs);
for (i=0; i<nrhs; i++) {
mexPrintf("\n\tInput Arg %i is of type:\t%s ",i,mxGetClassName(prhs[i]));
}
mexPrintf("\n\nThere are %d left-hand-side argument(s).\n", nlhs);
for (i=0; i<nlhs; i++) {
plhs[i]=mxCreateDoubleMatrix(1,1,mxREAL);
*mxGetPr(plhs[i])=(double)mxGetNumberOfElements(prhs[i]);
}
if (!initialized) {
cudaMalloc ((void **)&SkazalecGPU, sizeof(float)*vrsticaA*stolpecA);
initialized = 1;
//Zajem matrike
kazalecHost = (float *)mxGetPr(prhs[0]);
cudaMemcpy(SkazalecGPU, kazalecHost, sizeof(float)*vrsticaA*stolpecA, cudaMemcpyHostToDevice);
int **kpp;
plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT32_CLASS, mxREAL);
kpp =(int**) mxGetData(plhs[0]);
*kpp =(int *) &SkazalecGPU;
mexAtExit(cleanup);
} else {
mexPrintf("Matrika je ze na GPU enoti %d\n",&SkazalecGPU);
}
}
The second function is called like this [novaMatrika]=vrniMatrikoGPU(kazalecGPU):
#include "mex.h"
#include "cuda.h"
// [novaMatrika]=vrniMatrikoGPU(kazalecGPU)
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double kazalecGPU;
//stolpecA in vrsticaB morata biti iste velikosti
int vrsticaA = 3; /* preberemo stevilo vrstic A */
int stolpecA = 3; /* preberemo stevilo stolpcev A */
kazalecGPU = mxGetScalar(prhs[0]);
mexPrintf("vrednost na naslovu %d\n",kazalecGPU);
mexPrintf("naslov kazalcaGPU %d\n",&kazalecGPU);
int **kazalecPC;
plhs[0] = mxCreateNumericMatrix(3, 3, mxUINT32_CLASS, mxREAL);
kazalecPC = (int**) mxGetData(plhs[0]);
cudaMemcpy(kazalecPC, kazalecGPU, sizeof(float)*vrsticaA*stolpecA, cudaMemcpyDeviceToHost);
}
Basicaly first I just tried to get the right address in the second function but no luck :|
but in a function cudaMemcpy(pointerHost, pointerGPU, sizeof(float)*width*height, cudaMemcpyDeviceToHost);
The pointerGPU must be an address to the location of th matrix and not a value of a variable that I am returning from the first function.
So in short I would need an explanation on how to have a global pointer that is accessible from Matlab and from all mex functions if thats possible. If this is some kind of DLL I would be grateful for a little more detailed info on how to make it and how to declare it in a mex function.
Thanks,
David
-------------------------------------------
I will try to look at this some more later, but I have glanced at this code and have a few comments right away:
1) You have several different pointers being used and it seems confused. For instance, you get a variable from MATLAB as prhs[0], then access the data in that variable as float (probably 32-bit, i.e. single) via this line:
> kazalecHost = (float *)mxGetPr(prhs[0]);
then copy it into an int (probably 32-bit, i.e. int32 class) via a memory copy with this line:
> cudaMemcpy(SkazalecGPU, kazalecHost, sizeof(float)*vrsticaA*stolpecA, cudaMemcpyHostToDevice);
This is quite confusing to me. What, exactly, is the underlying data on the graphics card? Integer? I would use that type and stick to it. You are implicitly relying on float and int being the same length and are doing memory copies, so you aren't even using the data as float apparently. This is what is confusing and will probably confuse other readers as well.
Another issue is that this line:
> for (i=0; i<nlhs; i++) {
> plhs[i]=mxCreateDoubleMatrix(1,1,mxREAL);
is followed later on by this line:
> plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT32_CLASS, mxREAL);
i.e., you are putting two different things into plhs[0]. I am assuming that the first instance is just some debugging output and this isn't really a problem for you.
The biggest problem is of course the pointer is not being passed correctly. So here are some suggestions with a slight deviation from my original post using uint8 instead of uint32 to pass the address. You need to pass the value of SkazalecGPU from the first mex function to the second mex function. So simply allocate enough space to hold this value in some arbitrary MATLAB mxArray variable, put the value into the data area, and then recover it in the other mex function. For example:
In 1st mex function:
#include <string.h>
static int *SkazalecGPU; // assuming this is correct!
:
plhs[0] = mxCreateNumericMatrix(sizeof(SkazalecGPU)
, 1, mxUINT8_CLASS, mxREAL);
memcpy(mxGetData(plhs[0]),&SkazalecGPU,sizeof(SkazalecGPU));
This will return the value of the address contained in the variable SkazalecGPU back to the MATLAB workspace as the 1st returned variable (several bytes of the returned uint8 variable). The address itself is simply copied as the appropriate number of bytes into the data area of the return variable.
In 2nd mex function:
#include <string.h>
static int *SkazalecGPU; // make it the same as 1st function!
:
memcpy(&SkazalecGPU,mxGetData(prhs[0]),sizeof(SkazalecGPU));
i.e., just do the reverse byte copy to get the address back.
You were doing this:
> double kazalecGPU;
> kazalecGPU = mxGetScalar(prhs[0]);
which is totally wrong. The mxGetScalar will convert the value of prhs[0], a uint32 in the original code, into a double floating point value. This totally changes the bits of the data and completely wipes out the address you were trying to pass. Don't do any variable conversions here, just do a byte copy as I have shown so that the value stays exactly the same. And don't use a double variable to hold an address and try to pass that to a memory copy routine as an address.
I will look at the rest of your code later ...
James Tursa
What platform & compiler combination are you using? I may have a fiddle tomorrow. Can you confirm that sending and retrieving one pointer between two MEX functions is the goal?
- Steve
Hi I'm using Matlab 7.5.0, and Visual Studio 2005 Express (Microsoft Visual C++ 2005 compiler) on 32-bit Windows XP Professional SP3
My goal is to have one mex function that I will use to get Matrix from Matlab via C/CUDA combination on the GPU memory (and I need to "remember" where did I put that matrix-on what address on the GPU memory).
The second mex function would then be used to get another matrix from Matlab to C/CUDA environment and on the GPU memory, then read the matrix from the first mex function (that is already in the GPU memory) to make a matrix multiplication of both matrices and return the result back to Matlab.
To make that work I need to use the pointer to the matrix from the first mex function in the second mex function.
I'm part of a team working on the GPU Toolbox for Matlab: www.accelereyes.com. You can use it to do matrix multiplication as well as a host of other functions, and it'll take care of all the memory management for you. If you look in the documentaion/examples section of our site, you'll see that the first example lets you integrate custom CUDA code where you can pass pointers around safely.
-James Malcolm
Hi Malcolm,
The problem is that I can't use the Jacket engine because this is my diploma assignment and I must use just CUDA/C/Matlab implementation without other tools.
I just talked with my mentor and we agreed that we will now use just one mexfunction and rather have more input arguments in it and make all the necessary cumputations inside this one mexfunction.
Best regards,
David
This all sounds vey interesting. Will your report be open to see?
I think that it will be available.
FYI, to compile & link a DLL:
cl /O2 /D "NDEBUG" /D "_USRDLL" /D "WIN32" filename.c /LD
To export the symbols in the code:
__declspec(dllexport) myfunction()