Forum Discussion
C2H Compilation Error - Explicit Inclusion
I am currently attempting to performing C2H hardware acceleration of a computationally intensive processing algorithm, specifically Dynamic Time Warping or DTW, commonly used in speech and image processing.
I have selected the function I wish to accelerate in the Nios II IDE, but am faced with the following error when I try to build the project: c:/altera/91/nios2eds/components/altera_avalon_c_hardware_accelerator/c_code_block.pm 6055 called (c_code_block::user_message) where 'c2h:147: c2h error: could not find function malloc -- implementations of all subroutines called by accelerator_dtwserver_dtw_calcvectorcost_mxn_c2h must be in the same .c file or# included explicitly. at file: , line: 147' occurred on c:/altera/91/nios2eds/components/altera_avalon_c_hardware_accelerator/c_code_block.pm 6111 Why I am getting the error that the compiler can't find malloc? I have included reference to the <stdlib.h> header file and this is sufficient for the compiler to build normally (when C2H is not used). Any ideas on how I can go about resolving this error would be very much appreciated. Weird aye!11 Replies
- Altera_Forum
Honored Contributor
You aren't going to be able to convert a call to malloc() into VHDL!
The code to convert has to be a leaf function (or be convertable to one by inlining). - Altera_Forum
Honored Contributor
A general rule of thumb: don't rely on standard C libraries for anything you accelerate. Even if they were supported they would probably result in really big and slow hardware. The closest you can get is call malloc from outside the function and then pass in the pointer allocated by malloc to the accelerator.
Think of the accelerator that C2H generates as any standard IP block, it just happens to be generated from C code instead of being based on static Verilog/VHDL. Also I always say this to people I see using malloc: Do you *really* need to allocate your memory at run time? I ask because dynamic memory allocation can lead to problems (what happens in your system if malloc fails to return a pointer for example....) - Altera_Forum
Honored Contributor
Good points made dsl/BadOmen. I ended up rewriting the function so it only contains the math/recursive operators and no calls to external functions.
BadOmen: You're quite right about the use of malloc. Unfortunately in the case of my software, it is a necessary evil :) I have written a custom "array management" library in C which handles all the pointer allocation and error-catches if the desired array cannot be allocated (ie. a NULL pointer is returned). I'm processing dynamic 'chunks' of data received over TCP/IP on a Altera DE2 board - this data is comprised of single integer values, and more complex multidimensional integer arrays of variable length. I have written a custom library also which permits the transmission/reception of arrays between a Windows application transmitting over Winsock sockets, and Nichestack running on the Nios uCPU. Have added an additional handshaking layer which allows synchronisation between the two machines - usefully when you transferring a large multi-dim array ie. 50x10x20! Will post back soon on my progressing optimising my processing algorithm w/C2H. - Altera_Forum
Honored Contributor
Well have scrubbed out all function references in the code I am accelerating. Now, getting a new error which occurs when Quartus tried to compile the C2H-generated VHDL file (C2H compiler runs successfully):
error (10465): vhdl error at accelerator_dtwserver_dtw_calcvectorcost_mxn_c2h.vhd(20040): name "i0" cannot be used because it is already used for a previously declared item file: This is the function that I trying to optimise:int DTW_calcVectorCost_mxn_C2H(int **x, int xsize, int **y, int ysize, int nSize, int **Dist, int **globdist, int **move, int **temp, int **warp) { /* DESCRIPTION */ /* Compute a distance matrix on 2 multi-parameter vectors and perform dynamic time warping on the distance matrix */ int top, mid, bot, cheapest, total; int I, X, Y, n, i, j, k, cost; int params = nSize; /*Compute distance matrix*/ for(i=0;i<xsize;i++) { for(j=0;j<ysize;j++) { total = 0; for (k=0;k<params;k++) { total = total + ((x - y) * (x - y)); } Dist = total; } } /*% for first frame, only possible match is at (0,0)*/ globdist = Dist; for (j=1; j<xsize; j++) globdist = VERY_BIG_C2H; globdist = VERY_BIG_C2H; globdist = globdist + Dist; move = 2; for(j=2;j<xsize;j++) globdist = VERY_BIG_C2H; for(i=2;i<ysize;i++) { globdist = VERY_BIG_C2H; globdist = globdist + Dist; for(j=2;j<xsize;j++) { top = globdist + Dist + Dist; mid = globdist + Dist; bot = globdist + Dist + Dist; if( (top < mid) && (top < bot)) { cheapest = top; I = 1; } elseif (mid < bot) { cheapest = mid; I = 2; } else {cheapest = bot; I = 3; } /*if all costs are equal, pick middle path*/ if( ( top == mid) && (mid == bot)) I = 2; globdist = cheapest; move = I; } } X = ysize-1; Y = xsize-1; n=0; warp = X; warp = Y; while (X > 0 && Y > 0) { n=n+1; if (n>ysize *2) { return VERY_BIG_C2H; // Return default cost (large) if failed. // exit(1); } if (move == 1 ) { warp = X-1; warp = Y; n=n+1; X=X-2; Y = Y-1; } elseif (move == 2) { X=X-1; Y = Y-1; } elseif (move == 3 ) { warp = X; warp = Y-1; n=n+1; X=X-1; Y = Y-2; } else { return VERY_BIG_C2H; // Return default cost (large) if failed. } warp =X; warp =Y; } /*flip warp*/ for (i=0;i<=n;i++) { temp = warp; temp = warp; } for (i=0;i<=n;i++) { warp = temp; warp = temp; } // Cast 'globdist' as int 'cost' (to be returned) cost = globdist; return cost; } - Altera_Forum
Honored Contributor
Just some notes:
All the multidimensional pointer arrays used in the algorithm have already been allocated in memory by a previous function (non C2H). The address for each pointer is passed to the function. Now to simplify the function design, I have tried creating global variables for my pointer arrays in the C file. But the C2H compiler throws an error with this as it cannot determine the address in memory of these functions even after they are initialised (if not passed as a param to the function). This is all tested code btw. Running fine in C. - Altera_Forum
Honored Contributor
When you create a global variable used by the accelerated function C2H will create a master to access that value. Just like any other multi-core design, sharing data via global variables can be tricky. There are some corner cases of global variables that are documented that you should refer to in the C2H documentation.
If you are passing in a 2D set of data I recommend just passing in a pointer to the base address of this data and the row and column dimensions of this data as function parameters. I have a hunch that the issues you are running into are due to the fact that this accelerator is essentially it's own stand alone core, which has it's own view of the memory, without knowing what is cached by the Nios II processor, etc.... Basically treat the accelerator like it's a separate DMA engine and all the precautions that you would take with a DMA engine apply to a C2H accelerator as well. By the sounds of what you are doing, if your algorithm can handle multiple packets in flight you should take a look at the user guide in the section where it talks about adding interrupts. There are pragmas that you can add to make the accelerator non-blocking so if you can devise a scheme that you keep shoveling data at the accelerator you can eliminate any overhead of calling it multiple times. By doing this change you can make the accelerator behave even more like a dedicate hand coded accelerator and hide any overhead associated to offloading software into hardware. - Altera_Forum
Honored Contributor
Also make sure to read this doc, I tried to shovel as much information as possible into it: http://www.altera.com/literature/hb/nios2/edh_ed51005.pdf
- Altera_Forum
Honored Contributor
Appreciate all your input BadOmen - have printed everything out from the PDF and have some good reading ahead of me!
One thing though - the VHDL syntax error in the generated C2H HDL code, any ideas on what is causing that? As mentioned, the C2H compiler doesn't throw any errors, the SOPC system is generated successfully but when Quartus builds the project, it spits out the VHDL error above. - Altera_Forum
Honored Contributor
I'm not familiar with VHDL (I switched to verilog long ago and have never looked back :)). By the sounds of it the accelerated HDL happens to contain a previously declared module/name called "IO". Just in case there are old files being left behind one thing you could try is deleting all the generated HDL files and the /db directory for your project, and then regenerate to see if that will compile.
If that doesn't work then I would open the generated HDL file and search for "IO" in there to find out what is causing it to be used. - Altera_Forum
Honored Contributor
Thanks BadOmen, yes will look into what the error is in the VHDL syntax.
One thing though when I generate the accelerated HDL, the project directory is clean and there are no prev generated HDL files. Any ideas why the C2H compiler is generating HDL with errors in it? (as found by Quartus)?