自己动手,实现在kernel函数中printf()!(转)

在非EMU模式下,CUDA kernel函数中不能调用任何标准库函数,自然也就不能调用printf。这给我们调试CUDA程序带来了极大的不便。为此,最近nVidia已经专门开发了一个cuprintf()函数,不过目前还在内部测试中,普通用户暂时还无法看到。

其实,我们利用CUDA现有的功能自行开发一个类似的函数也并不是很困难。自己动手,丰衣足食。本文中的给出的小程序就是这样一个简单的实现。这是一个完整的测试程序,可以直接在VS2008上运行。在真正的device中printf()和在EMU模式下printf()感觉是不一样的,大家可以尝试一下。

使用方法和局限性:
1、只要首先在host端调用device_printf_init()初始化,然后就可以在kernel函数中像printf()一样调用device_printf()了。

2、由于device函数一般不支持可变参数,为简单起见,本文实现的device_printf只支持1个或2个参数,暂时只支持'%d', '%u', '%f', '%c'这几种描述符。以下用法都是允许的:
  device_printf("1+1=%d/n", 2);
  device_printf("A+B=%c/n", 'C');
  device_printf("1/2=%f/n", 1/2.0);
  device_printf("unsigned(-1)=%u/n", -1);
  device_printf("OK, test passed./n");

3、输出结果会自动flush(), 默认flush()时间是200ms,可以通过修改宏参数PRINTF_FLUSH_INTERVAL调整。

4、打印缓冲区默认为4096 (PRINTF_BUFFSER_SIZE),如果打印太快(200ms内超过4096字节)会发生溢出。溢出的后果是造成部分打印结果丢失。其他没什么副作用。

由于程序写得匆忙,还没有仔细检查。欢迎报告bug。

C/C++ code
   
   
/* * device_printf.h - my own implemetation of 'cuprintf', enable limited printf() from device * v0.1 by cuda2010 @ csdn, Feb 21, 2010 */ #ifndef DEVICE_PRINFT_H #define DEVICE_PRINTF_H #include " cutil_inline.h " #include " windows.h " #pragma comment(lib, "winmm.lib") using namespace std; #define PRINTF_BUF_SIZE 4096 #define PRINTF_FLUSH_INTERVAL 200 struct BUFFER { char data[PRINTF_BUF_SIZE]; unsigned int ptr; } * host_buffer; __device__ struct BUFFER * device_buffer; static void CALLBACK device_printf_flush(UINT uid, UINT umsg, DWORD dwusr, DWORD dw1, DWORD dw2) { static int old_ptr; int ptr = (host_buffer -> ptr) % PRINTF_BUF_SIZE; if (old_ptr <= ptr) { for ( int i = old_ptr; i < ptr; i ++ ) { printf( " %c " , host_buffer -> data[i]); } } else { for ( int i = old_ptr; i < PRINTF_BUF_SIZE; i ++ ) printf( " %c " , host_buffer -> data[i]); for ( int i = 0 ; i < ptr; i ++ ) printf( " %c " , host_buffer -> data[i]); } old_ptr = ptr; } __global__ void set_device_buffer( void * ptr) { device_buffer = ( struct BUFFER * )ptr; } void device_printf_init() { static int inited = 0 ; void * ptr; if (inited) return ; timeSetEvent(PRINTF_FLUSH_INTERVAL, 0 , device_printf_flush, 0 , (UINT)TIME_PERIODIC); cutilSafeCall(cudaSetDeviceFlags(cudaDeviceMapHost)); cutilSafeCall(cudaHostAlloc(( void ** ) & host_buffer, sizeof ( struct BUFFER), cudaHostAllocMapped)); memset(host_buffer, 0 , sizeof ( struct BUFFER)); cutilSafeCall(cudaHostGetDevicePointer(( void ** ) & ptr, host_buffer, 0 )); set_device_buffer <<< 1 , 1 >>> (ptr); cudaThreadSynchronize(); inited = 1 ; } __device__ int sprintf_int( char * s, int v) { int len = 0 ; if (v == 0 ) { s[ 0 ] = ' 0 ' ; return (len = 1 ); } if (v < 0 ) { s[len ++ ] = ' - ' ; v =- v; } unsigned int base ; for ( base = 1000000000 ; base > 0 ; base /= 10 ) if ((unsigned int )v >= base ) break ; while ( base > 0 ) { s[len ++ ] = ' 0 ' + (v / base ) % 10 ; base /= 10 ; } return len; } __device__ int sprintf_uint( char * s, unsigned int v) { int len = 0 ; if (v == 0 ) { s[ 0 ] = ' 0 ' ; return (len = 1 ); } unsigned int base ; for ( base = 1000000000 ; base > 0 ; base /= 10 ) if (v >= base ) break ; while ( base > 0 ) { s[len ++ ] = ' 0 ' + (v / base ) % 10 ; base /= 10 ; } return len; } __device__ int sprintf_float( char * s, double v) { int len = 0 ; if (isinf(v)) { s[len ++ ] = ' I ' ; s[len ++ ] = ' N ' ; s[len ++ ] = ' F ' ; return len; } if (isnan(v)) { s[len ++ ] = ' N ' ; s[len ++ ] = ' A ' ; s[len ++ ] = ' N ' ; return len; } if (v < 0 ) { s[len ++ ] = ' - ' ; v =- v; } double e = log10(v); int a, b; if (isinf(e)) e = 0 ; b = ( int )e; if (b < 0 ) b -- ; a = ( int )(v / pow( 10.0 ,b) * 1000000 + 0.5 ); s[len ++ ] = ' 0 ' + (a / 1000000 ) % 10 ; s[len ++ ] = ' . ' ; s[len ++ ] = ' 0 ' + (a / 100000 ) % 10 ; s[len ++ ] = ' 0 ' + (a / 10000 ) % 10 ; s[len ++ ] = ' 0 ' + (a / 1000 ) % 10 ; s[len ++ ] = ' 0 ' + (a / 100 ) % 10 ; s[len ++ ] = ' 0 ' + (a / 10 ) % 10 ; s[len ++ ] = ' 0 ' + (a) % 10 ; s[len ++ ] = ' E ' ; s[len ++ ] = (b < 0 ) ? ' - ' : ' + ' ; b = abs(b); s[len ++ ] = ' 0 ' + (b / 100 ) % 10 ; s[len ++ ] = ' 0 ' + (b / 10 ) % 10 ; s[len ++ ] = ' 0 ' + (b) % 10 ; return len; } __device__ int sprintf_str( char * s, char * s2, int maxlen) { int i; for (i = 0 ; s2[i] && i < maxlen; i ++ ) s[i] = s2[i]; return i; } __device__ int do_device_printf( char * s, int len) { unsigned int from = atomicAdd( & (device_buffer -> ptr), len); for ( int i = 0 ; i < len; i ++ ) device_buffer -> data[(from + i) & (PRINTF_BUF_SIZE - 1 )] = s[i]; return len; } template < class TYPE > __device__ int device_printf(TYPE fmt) { char * s = ( char * )fmt; int len; for (len = 0 ; s[len] && len < 255 ; len ++ ); do_device_printf(s, len); return len; } template < class TYPE > __device__ int device_printf( char * fmt, TYPE a) { char buf[ 300 ]; int i, j; for (i = j = 0 ; fmt[i]; i ++ ) { if (j >= 255 ) break ; if (fmt[i] != ' % ' ) { buf[j ++ ] = fmt[i]; continue ; } if (fmt[i + 1 ] == ' d ' ) { j += sprintf_int(buf + j, a); } else if (fmt[i + 1 ] == ' u ' ) { j += sprintf_uint(buf + j, a); } else if (fmt[i + 1 ] == ' c ' ) { buf[j ++ ] = a; } else if (fmt[i + 1 ] == ' f ' ) { j += sprintf_float(buf + j, ( double )a); } i += 2 ; j += sprintf_str(buf + j, fmt + i, 255 - j); break ; } if (j > 255 ) j = 255 ; buf[j] = 0 ; return do_device_printf(buf, j); } #endif // end of DEVICE_PRINFT_H // main.c __global__ void cuda1() { int inx = blockIdx.x * blockDim.x + threadIdx.x; float sum = 0 ; device_printf( " Thread %d starts/n " , inx); for ( int i = 1 ; i < 20000000 ; i ++ ) { sum += ( float )i * i / 10.0f ; if (i % 1000000 == 0 ) { device_printf( " Thread %d:/n " , inx); device_printf( " i=%d/n " , i); device_printf( " sum=%f/n " , sum); } } device_printf( " Thread (%c) is finished/n " , inx + ' A ' ); } int main() { device_printf_init(); cuda1 <<< 4 , 4 >>> (); cudaThreadSynchronize(); }
(转自:http://topic.csdn.net/u/20100221/12/85d9155c-f7d3-4edf-a3f6-3af3d0bb6835.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值