0

Hey there, I have the following code-snippet:

double *f;
f = a_function(parameters...); 
printf("%f", *(f+1));
loopAry(f, 5);

void loopAry(double *in, int size)
{   
    printf("%f\n", *(in+1));
    for(int i = 0; i < size; i++) 
    {
        printf("\nin[%d]=%f  ", i, *(in+i));
    }
}

(mex-file in matlab). Now the problem is: I have found two solutions before how to compile mex-files with CUDA in it and I figured out that when I compile it with the first method, the above code works as it should, and if I compile it with the second method, the code just doesn't run. Now I wonder, if the code contains anything suspicious what COULD eventually cause some problems?

Method one does the output (this is correct behaviour):

1.000000  1.000000

in[0]=1.000000  
in[1]=1.000000  
in[2]=1.000000  
in[3]=1.000000  
in[4]=1.000000  

and the second does the following:

1.000000 0.000000

in[0]=0.000000  
in[1]=90932971983710041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000  
in[2]=90932971983710041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000  
in[3]=90932971983710041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000  
in[4]=90932971983710041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000  

so there's something wrong with passing the data via pointer, since the output of the the second element (printf("%f", *(fVec0_+1));) works as it is supposed to work... but NOT after calling loopArray()...

To clarify the two compiling methods: FIRST (working) Execute this script: http://www-europe.mathworks.com/matlabcentral/fileexchange/25314-cuda-mex which makes a new m-file to compile like the usual mex-script (just with CUDA included) :-)

SECOND (not working) (found on http://forums.nvidia.com/index.php?showtopic=172175)

function nvc(filename)

options='-arch=sm_21';
options=[options ' --use_fast_math'];
txt=sprintf('"C:\\Program Files (x86)\\NVIDIA GPU Computing Toolkit\\CUDA\\v3.2\\bin\\nvcc" %s.cu %s -c -lcufft -lcudart -lcublas -lcuda --ptxas-options=-v -IJ:\\MATLAB32bitR2010b\\extern\\include\\',filename,options);
system(txt)
mex_options='-O'; % enable optimisation
n=getenv('CUDA_LIB_PATH');
mex(['-L' n],mex_options,'-lcudart','-lcufft','-lcublas','-lcuda',sprintf('%s.obj',filename));
delete(sprintf('%s.obj',filename));

EDIT This is the function which returns the pointer:

double *a_function(const mxArray *point)
{
    double *dat = mxGetPr(point);   
    double vals[ 5 ] = {
dat[0]*dat[0]*dat[0],
dat[1]*dat[1]*dat[1],
dat[2]*dat[2]*dat[2],
dat[3]*dat[3]*dat[3],
dat[4]*dat[4]*dat[4]};
    double *pnt = vals;

    return pnt;
}
tim
  • 9,896
  • 20
  • 81
  • 137
  • 1
    How does `a_function` create the array it returns? – sth May 09 '11 at 15:22
  • Oh thanks for pointing me to that, I'll post it right now in the first post!! – tim May 09 '11 at 15:24
  • Do you get any CUDA errors? Is there any device code to begin with? – Bart May 09 '11 at 15:26
  • Currently I'm not using CUDA in this code; but I setup the compiler to compile with CUDA since I want to integrate CUDA soon :) – tim May 09 '11 at 15:32

2 Answers2

3

You declare the array as a local variable that will go out of scope at the end of the function. The f pointer than points to the location where the array used to be but isn't anymore.

You should dynamically allocate the array:

double *vals = new double[5];
vals[0] = dat[0]*dat[0]*dat[0];
vals[1] = dat[1]*dat[1]*dat[1];
// ... 

// Or use a for-loop for the initialization:
for (int i=0; i<5; i++)
   vals[i] = dat[i]*dat[i]*dat[i];

When you are done with the array, delete it again:

delete[] f;
sth
  • 222,467
  • 53
  • 283
  • 367
  • Thanks so far! So I would have `double *vals = new double[5]; vals = { CODE FROM ABOVE ... }; *pnt = vals; return pnt;` correct? :-) **EDIT**: Okay thanks, so there's no way to initialize it completely in one step? – tim May 09 '11 at 15:35
  • 1
    @Col: You can't use the `{...}` initializer syntax in this case but have to "manually" initialize the values like `val[0] = ...`. I added that to the code in my answer. – sth May 09 '11 at 15:39
  • Just saw it. It's a pity, but okay, that's not too bad :-) One more question: the `delete[] f;` has to be at the really end of my program where I don't need `f` anymore, right? **EDIT**: So this is a general thing? Everytime I have a function which returns an array I need to create it dynamically and return a pointer to it? – tim May 09 '11 at 15:41
  • @Col: Do the `delete[]` when you are done with the array and that memory can be used again for other things. Every array that gets allocated with `new double[5]` when you call `a_function` should be deallocated with `delete[]` once it's not used anymore. – sth May 09 '11 at 15:44
  • Okay thanks. Do you have any good link explaining this topic, why I can't do it with "non-dynamic" arrays? I just want to understand it completely :) – tim May 09 '11 at 15:45
  • OKay now the probably last question about it. I assume that when I have something like: `double *f; for(int i = 0; i < 10; i++) { f=a_function(...); }` I only have to delete f once at the end, right? Or do I have to `delete[] f` at the end of each loop? – tim May 09 '11 at 15:54
  • 1
    You have to delete `f` at the end of each loop. The `delete[]` doesn't delete the `f` itself, it deletes the array `f` points to. Since every call to `a_function` creates a new array, each of those arrays needs to be deleted. Else all those arrays will still be around and use up memory, even though nobody uses them anymore. The difference between "non-dynamic" vs. "dynamic" arrays is that between allocation on the [stack and the heap](http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap). a_func returned a pointer to an array on the stack, `new` allocates on the heap. – sth May 09 '11 at 16:11
  • Hm okay thanks again! I'll try to figure it out! So the following would be the correct way to do it!? -> `f=a_funtion(); for(int i = 0; i < 5; i++) { ...some calculations with f...; delete[] f; f=a_funtion(); } delete[] f;`? – tim May 09 '11 at 16:33
  • @Col: Simpler would be: `for(int i = 0; i < 5; i++) { f = a_function(); ...some calculations with f...; delete[] f; }` – sth May 09 '11 at 16:35
1

The function a_function is returning an array that's allocated on its stack. As soon as a_function returns, the array is invalid. Under some circumstances -- and compiler flags will affect this -- the array will appear to be partially or wholly available, but strictly it's garbage. You must allocate the array using new if you need to return a pointer to it from a function.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186