08-15-2012 09:02 PM
Hi all. I recently finished writing a CUDA dll for LabView, and now I am in the stages of optimizing the code, memory management, etc. BUT since My code is dependent on Labview Inputs (a lot of data in labview specific datatypes like Array Handles and Clusters) I am unable to use the CUDA profiler, or the VC++ profiler on the DLL. What I plan on doing is running labview, and then outputting all the input data for the DLL into a binary file, and then add an extra function in my code that will read in the binary file, allocate and assign all the variables to their respective position, and then call the Labview Specific DLL function. ULTIMATELY, this miniature function will act as the Call Library Function for my specific group of data inputs.
Anyway, I started doing this buy clustering all my data input, and outputting it into a binary file. And then I started initializing labview handles, allocating memory, and starting writing the data from the binary file into the memory, and this works for ints, floats, etc, but I am confused on how it works with Array Handles!
Here is some example code:
//Defines 1d Array Handle for INT typedef struct { int length; int val[1]; //to access value at a row => val[row] } Array1dInt, **Array1dIntHandle; int main() { Array1dIntHandle x = new Array1dInt*; (*x) = new Array1dInt; ifstream file ("TESTDATAIN.dat", ios::in|ios::binary); if(file.is_open()) { file.read((char *)&(*x)->length, sizeof(int)); file.read((char *)&(*x)->val[0], sizeof(int)*(*x)->length); LabviewSpecificFunction( x ); file.close(); } else { cout << "File Did Not Open!" << endl; } return 0; } __declspec(dllexport) LabviewSpecificFunction ( Array1dIntHandle x ) { ... }
However, my program crashes when the array is nominally big, and this is expected because if we look at the Array1dHandle, it has only allocated enough memory for 1 value element! YET, somehow, labview in its magical and mysterious ways is able to make val[1] be val[HOWEVERMANYYOUWANT], even though C++ 101 says that val[1] is a constant pointer, and even if I dynamically allocated memory somwhere else, I would never be able to put this data into this handle!
Can someone explain, or maybe even write example code on how I can trick my program into thinking the binary file is coming from labview, so I can then run my program independent of labview allowing me to profile the functions inside of it?
I hope this question is clear, and my example code is clear aswell, but I am happy to answer any and all questions that relate to this.
Thanks all!
Solved! Go to Solution.
08-16-2012 12:54 PM
I think I figured it out.
Array1dIntHandle x = new Array1dInt*;
int tempsize; file.read((char *)&tempsize, sizeof(int)); (*x) = (Array1dInt*)malloc(sizeof(int) + sizeof(int)*tempsize); (*x)->length = tempsize; file.read((char *)&(*x)->val[0], sizeof(int)*(*x)->length);
Pretty much you need to make the handle, then make a new Array1dInt* for it, then read in the length of the array into a temp variable. Then use that information to then malloc the amount of memoery you need for the array, and pass that location to the handle. Now the handle will point to that memory size, and you will be able to acess the memory in the format you made the handle. badabing badaboom
08-16-2012 12:55 PM
Why did you prefer to use LabVIEW-specific data formats instead of standard C ones? You can pass an array from LabVIEW to a DLL as a standard C array, which will be much easier. The only reason I can see for using the LabVIEW-specific data types is if you need to manipulate the memory allocations using the LabVIEW Manager functions (documented in the LabVIEW help). Clusters can similarly be passed directly as structs (occasionally you may need to add padding to the cluster).
08-16-2012 01:35 PM - edited 08-16-2012 01:36 PM
Can you show me how I would send it as a normal C array? All resources that I have ever seen on working with Labview and DLLs told me to use Handles. As for Clusters, they are equivalent to structs, so in my code there is nothing special going on there, but whereever there is an array, I have a Handle.
Honestly though, please show me what settings to put in the Call Library function
EDIT: Also remember that I am working with multidimensional arrays, and in all cases, I need to know the dimensions of the array, which a Handle allows me to access really easily without sending in 2 or 3 ints per array.
08-16-2012 01:56 PM - edited 08-16-2012 01:57 PM
Deturbanator wrote:Honestly though, please show me what settings to put in the Call Library function
EDIT: Also remember that I am working with multidimensional arrays, and in all cases, I need to know the dimensions of the array, which a Handle allows me to access really easily without sending in 2 or 3 ints per array.
Ah, you didn't mention that in your original post, and the example you provided is a 1D array. In that case the array handle may be best.
For a 1D array you configure the Call Library Function with the parameter Type as Array and the Array format set to Array Data Pointer.
You may have already seen this note in the help, but if you are resizing the arrays in your code, make sure you use the LabVIEW Manager functions and not the C/C++ memory allocation functions.
08-16-2012 02:39 PM
An n-dimensional array is is simply a memory buffer with the sizes of all dimensions multiplied. So there is no real difference in passing a 1D array or a 3D array if you pass them as C pointer. They are both really a single pointer to an array of elements. For the passing of the sizes you then have to pass an array of ints instead of a single int but that is also not a big problem. As far as creating LabVIEW handles is concerned, you definitely shouldn't create them yourself with malloc() if the handle gets passed to anything that is LabVIEW, such as a LabVIEW created DLL. This DLL expects the handles to be created with the DS.. tyypes of functions from the LabVIEW runtime kernel that loaded the DLL. If you pass something else to such functions, even if it is logically like a handle, the LabVIEW code will trip over it.
Same issue as would be if you call a DLL that is linked to a different version or type of C runtime library and you create a memory pointer in one module and pass it to the other one. Since each C runtime manages it's own type of memory allocations, that leads to nasty problems, as a pointer created in one runtime is not the same as a pointer created in the other runtime, since they are often located on different process heaps.
08-16-2012 05:11 PM
Thanks, but I did know about the pass as pointer option, however it seemed to me at the time of writing everythign that passing as a Handle made more sense since it was all put together (the dimension sizes and values) in a single object. Again my goals is to SIMULATE labview so I can run my program through a profiler, a task which is currently impossible since I am dependent on input from labview. None of what I am doing will ever see the labview world, this is merely a means to test without having to depend on labview.
08-17-2012 02:21 AM - edited 08-17-2012 02:28 AM
@Deturbanator wrote:
Thanks, but I did know about the pass as pointer option, however it seemed to me at the time of writing everythign that passing as a Handle made more sense since it was all put together (the dimension sizes and values) in a single object. Again my goals is to SIMULATE labview so I can run my program through a profiler, a task which is currently impossible since I am dependent on input from labview. None of what I am doing will ever see the labview world, this is merely a means to test without having to depend on labview.
I take your word for it but I'm a bit confused about what you try to do. You write a DLL and a test framework for that DLL of some sorts and the DLL should have a LabVIEW interface, but neither the DLL will be ever used in LabVIEW nor de test framework to exercise LabVIEW DLLs? What's the point in this exercise? As to emulating the Call Library Function Node work, a simple LoadLibrary() and GetProcAddress() are the obvious parts of this, yet that is maybe 2% of the code concerned with the Call Library node. The rest is preparing the stack, massaging the various data onto the stack including converting from LabVIEW data to C type data where necessary, setting up exception handling around the call to be able to recover at least from some of the possible errors, and after the call retrieve any output parameters from the stack and also the return value, possibly converting back to LabVIEW data.
Most of this is done automatically by a normal C compiler, but the Call Library Node needs to set this all up at compile time from the configuration dialog. So emulation is possible but don't expect an exact same behaviour in your C compiler call setup.
Talk about adding a completly unneccessary constrain on your work in that case.