A.6_Error_Handling

A.6 Error Handling

chError.h implements a set of macros that implement the goto-based error handling mechanism described in Section 1.2.3. These macros do the following.

  • Assign the return value to a variable called status

  • Check status for success and, if in debug mode, report the error to stderr

  • If status contains an error, goto a label called Error

The CUDA runtime version is as follows.

ifdef DEBUG
	#define CUDART_CHECK( fn ) do \{
	(status)  $= \left( \mathrm{{fn}}\right) ;$ 
		if ( CUDASuccess != (status)) \{
			fprintf( stderr, "CUDA Runtime Failure (line %d of file %s):\\n\\t" \\ )
		"\%s returned 0x%x (%s)\\n", \ _
		"LINE_, _FILE_, #fn, status,udaGetErrorString(status)); \
		goto Error; \
	\}
	while (0);
	#else
	#define CUDART_CHECK( fn ) do \{
	.status = (fn); \
		if ( CUDASuccess != (status)) \{ \
			goto Error; \}
	\}
	while (0);
	#endif

The do..while is a C programming idiom, commonly used in macros, that causes the macro invocation to evaluate to a single statement. Using these macros will generate compile errors if either the variable status or the label Error: is not defined.

One implication of using goto is that all variables must be declared at the top of the block. Otherwise, some compilers generate errors because the goto statements can bypass initialization. When that happens, the variables being

initialized must be moved above the first goto or moved into a basic block so the goto is outside their scope.

Listing A.4 gives an example function that follows the idiom. The return value and intermediate resources are initialized to values that can be dealt with by the cleanup code. In this case, all of the resources allocated by the function also are freed by the function, so the cleanup code and error handling code are the same. Functions that will only free some of the resources they allocate must implement the success and failure cases in separate blocks of code.

Listing A.4 Example of goto-based error handling.

double   
TimedReduction( int \*answer, const int \*deviceIn,size_t N, int cBlocks,int cThreads, pfnReduction hostReduction   
) { double ret  $= 0.0$  int \*deviceAnswer  $= 0$  int \*partialSums  $= 0$  ); JudaEvent_t start  $= 0$  ; JudaEvent_t stop  $= 0$  ; JudaError_t status; CUDART_CHECK( JudaMalloc( &deviceAnswer,sizeof(int))); CUDART_CHECK( JudaMalloc( &partialSums,cBlocks\*sizeof(int))); CUDART_CHECK( JudaEventCreate( &start)); CUDART_CHECK( JudaEventCreate( &stop)); CUDART_CHECK( JudaThreadSynchronize()); CUDART_CHECK( JudaEventRecord( start,0)); hostReduction( deviceAnswer, partialSums, deviceIn, N, cBlocks, cThreads); CUDART_CHECK( JudaEventRecord( stop,0)); CUDART_CHECK( JudaMemcpy( answer, deviceAnswer, sizeof(int), JudaMemcpyDeviceToHost)); ret  $=$  chEventBandwidth( start,stop,N\*sizeof(int))/ powf(2.0f,30.0f);
// fall through to free resources before returning  
Error:  
   企业提供 deviceAnswer();  
   企业提供 partialSums();  
    eventDestroy( start );  
    eventDestroy( stop );  
    return ret;

This page intentionally left blank