OpenCL计算时间比CPU替代时间长得多

时间:2011-11-22 12:34:57

标签: opencl

我正在OpenCL(和CUDA)的第一步实习。一切都很好,我现在已经有了OpenCL代码,但是我认为计算时间太长了。我的猜测是我做了太多I / O,但我不知道那可能是什么。

代码用于主要:http://pastebin.com/i4A6kPfn,对于内核:http://pastebin.com/Wefrqifh我开始测量segmentPunten(segmentArray, begin, eind);返回后的时间,并且我在最后一次测量时间结束clEnqueueReadBuffer

Nvidia GT440的计算时间为38.6秒,GT555M 35.5,Athlon II X4 5.6秒,英特尔P8600 6秒。

有人可以向我解释一下吗?为什么计算时间如此之高,有什么解决方案呢?

它应该做什么:(简短版本)计算一架飞过的飞机所产生的噪音。

长版本:有几个观察点(OP),它是从飞机经过的飞机测量的声音点。飞行路径在10,000个段中被分段,这在功能segmentPunten中完成。 main中的double for循环为OP提供了一个坐标。有两个内核。第一个计算从单个OP到单个段的距离。然后将其保存在“afstanden”数组中。第二个内核计算来自所有段的OP中的声音负载。

3 个答案:

答案 0 :(得分:3)

只要注意你的内核,我就看到了:

kernel void SEL(global const float *afstanden, global double *totaalSEL, 
    const int aantalSegmenten)
{
    // ... 
    for(i = 0; i < aantalSegmenten; i++) {
        double distance = afstanden[threadID * aantalSegmenten + i];
        // ...
    }
    // ...
}

看起来aantalSegmenten被设置为1000.每个都有一个循环 访问全局内存1000次的内核。没有抓取代码, 在考虑你的时候,我猜这些访问很多都是重叠的 计算作为一个整体。这是这样的吗?两个工作项是否会访问相同的内容 全球记忆?如果是这种情况,你会看到一个潜在的巨大胜利 GPU可以重写您的算法,对工作进行分区,以便您可以阅读 从特定的全局内存只有一次,将其保存在本地内存中。之后, 工作组中需要该位置的每个工作项都可以快速读取。

另外,CL规范允许您省略CL中的前导__ 关键字如globalkernel。我不认为很多新人会认识到CL 这一点。

答案 1 :(得分:1)

在进一步优化之前,您应该首先了解一直在做什么。是内核编译,数据传输还是实际的内核执行?

如上所述,您可以通过缓存结果来摆脱内核编译。我相信一些OpenCL实现(至少是Apple的实现)已经自动完成了。对于其他,您可能需要手动执行缓存。 Here's instructions for the caching.

如果性能瓶颈本身就是内核,那么通过以不同方式组织'afstanden'数组查找,您可能会获得大幅加速。目前,当一个线程块执行从内存中读取时,地址通过内存展开,这是GPU性能的真正杀手。理想情况下,您希望使用类似afstanden[ndx*NUM_THREADS + threadID]的索引来索引数组,这将使工作组的访问加载连续的内存块。这比当前的,基本上随机的内存查找快很多

答案 2 :(得分:0)

首先,您要测量的不是计算时间,而是整个内核读入/编译/执行mumbo-jumbo。要进行公平的比较,请测量程序中第一个“非静态”部分的计算时间。 (例如,从第一个clSetKernelArgs到最后一个clEnqueueReadBuffer之间。)

如果执行时间仍然太长,那么您可以使用某种分析器(例如NVidia的VisualProfiler),并阅读CUDA Toolkit文档中包含的OpenCL Best Practices guid。

原始内核执行时间:考虑(并测量)您真正需要计算的双精度,因为双精度计算在消费级NVidia卡上被人为减慢。