3

也许(或者不是也许)我以错误的方式做某事,但似乎我无法从 OpenCl 内核中获得良好的性能,即使它在 GPU 上的运行速度比在 CPU 上快得多。

让我解释。

CPU 内核运行时间约为 100 毫秒。
GPU 内核运行时间约为 8 毫秒。

以上是使用clCreateCommandQueuewithCL_QUEUE_PROFILING_ENABLE标志测量的。

但是,问题是重复调用(入队)内核所需的时间。

CPU 上 200 次内核调用:~19
秒 GPU 上 200 次内核调用:~18 秒

gettimeofday以上是通过在 200 循环之前和之后调用来测量的。就在循环之后,调用clFinish等待直到 200 个排队的内核完成。
此外,时间仅针对入队和执行内核进行测量,不涉及从/到内核的数据传输。

这是循环:

size_t global_item_size = LIST_SIZE;
Start_Clock(&startTime);
for(int k=0; k<200; k++)
{
    // Execute the OpenCL kernel on the list
    ret = clEnqueueNDRangeKernel (command_queue, kernel, 1, NULL, &global_item_size, NULL, 0, NULL, &event);        
}   
clFinish(command_queue);    
printf("] (in %0.4fs)\n", Stop_Clock(&startTime));

如果对内核的 200 次调用需要大约 18 秒,那么 GPU 上的内核比 CPU 上的内核快几倍是完全无关的......

我究竟做错了什么?


编辑

我做了一些额外的测试,似乎实际上将计算结果分配给输出缓冲区会产生开销。

这个内核

__kernel void test_kernel(__global const float *A, __global const float *B, __global float *C) 
{
    // Get the index of the current element to be processed
    int i = get_global_id(0);

    // Do the work
    C[i] = sqrt(sin(A[i]) + tan(B[i]));
}

执行 200 次的时间如上。但是,如果我将C[i]行更改为,
float z = sqrt(sin(A[i]) + tan(B[i]));
那么这个内核在 CPU 上需要 0.3 秒,在 GPU 上需要 2.6 秒。

有趣的。我想知道是否可以通过在表中收集结果然后仅在执行最后一次内核调用时将它们分配给输出缓冲区
来加快执行速度?(具有最后一个全局 id 的内核,而不是第 200 个入队的内核)__localC

4

0 回答 0