【发布时间】:2014-06-09 20:44:35
【问题描述】:
我想确保clEnqueueReadBuffer() 的测量时间正确,如何测量将数据从 GPU 复制到主内存所需的时间。我有点怀疑clFinish() 也有贡献。
我运行 1000000 个浮点数的 100 倍点积并以此测量时间
// RUN TIME BLOCK
println( " Running OpenCL program ... " );
t1 = System.nanoTime();
for (int reps = 0; reps < 100; reps++) {
clEnqueueNDRangeKernel(commandQueue, kernel, 1, null, global_work_size, local_work_size, 0, null, null);
}
clFinish(commandQueue); // VERSION 1
t2 = System.nanoTime();
println( " OpenCL Run Time : "+ ((t2-t1)*1e-9)+" [s] " );
// READ OUT TIME BLOCK
t1 = System.nanoTime();
//clFinish(commandQueue); // VERSION 2
clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE, 0, n * Sizeof.cl_float, dst, 0, null, null);
t2 = System.nanoTime();
println( " Read-out Time: "+ ((t2-t1)*1e-9)+" [s] " );
得到结果
OpenCL Run Time : 2.5124469 [s]
Read-out Time: 0.002145424 [s]
这对我来说似乎有点太好了,只有 2 毫秒和
当我将 clFinish(commandQueue); 放入 Read-out Time 块中时,我得到了这些结果
OpenCL Run Time : 1.0892084 [s]
Read-out Time: 1.4300439 [s]
另一方面,这似乎太糟糕了……在 GPU 上进行 100 次乘法比通过 PCI-express 复制它更快? ....也许
只是为了完整性:
我为processing 使用了openclp5 库,它在带有Quadro FX 580 GPU 的Ubuntu 12.04 64 位和Java jdk 1.7 上使用jocl 和
我的内核很简单(没有优化或任何东西)
String programSource =
"__kernel void sampleKernel( "+
"__global const float *a, __global const float *b, __global float *c) { "+
" int gid = get_global_id(0); "+
" c[gid] = a[gid] * b[gid]; "+
"}";
【问题讨论】:
-
任何“clEnqueue*”命令都是这样做的:enqueueing。您只是在测量向队列添加内容的开销。如果您想知道复制所需的时间,您需要添加 clFinish。或者使用 OpenCL 事件和命令队列分析。
-
嗨,我很清楚,为了测量 OpenCL 程序的运行时间,有必要计算
clFinish(),但我不清楚,如果测量clEnqueueReadBuffer()确实如此包括将数据从 GPU 复制到 RAM 所需的所有时间,或者如果此操作的一部分已在clFinish()中完成 -
clEnqueueReadBuffer排队工作。工作在不久之后异步开始。clFinish本身并不做工作,它只是等待所有工作完成。如果工作没有完成,它会阻塞并且在它完成之前不会返回。如果工作已经完成(可能是因为你开始计算 pi 到一百万位),那么clFinish就会返回。因此,如果您从调用clEnqueueReadBuffer之前到调用clFinish之后进行计时,那么您就是在计算复制所需的时间,以及一些较小的 API 开销。 -
aha 好吧,我第一次在
clEnqueue*中没有得到那个*。现在我知道我必须在clEnqueueReadBuffer之后再打电话给clFinish() -
您不需要在
clEnqueueReadBuffer之后调用clFinish,因为您设置了阻止标志。这是一个隐含的clFinish。
标签: java performance profiling opencl