OpenCL AMD与NVIDIA性能比较

8
我实现了一个简单的卷积核。我在NVIDIA GT 240 上进行了测试,CUDA写的时候需要70ms,OpenCL写的时候需要100ms。我想,可能是NVIDIA编译器优化了CUDA(或者我做错了什么)。然后我需要在AMD GPU上运行它,所以我迁移到了AMD APP SDK。使用完全相同的核代码进行了两个测试。对我来说,结果很令人沮丧:HD 6670花费了200毫秒,HD 5850花费了70毫秒(与GT 240 + CUDA相同的时间)。我非常想知道这种奇怪行为的原因。所有项目都是在VS2010上构建的,使用了分别来自NVIDIA和AMD的样本项目的设置。
请不要将我的帖子视为NVIDIA广告。我非常清楚HD 5850比GT 240更强大。我唯一想知道的是为什么会有这样的差异,以及如何解决问题。
更新。以下是核心代码,它在基础图像中查找6个大小相等的模板图像。基本图像的每个像素都被认为是其中一个模板的可能起点,并由单独的线程处理。内核比较基本图像和模板图像的R、G、B值,如果至少有一个差异超过“diff”参数,则计算相应像素不匹配。如果不匹配像素的数量小于“maxNonmatchQt”,则击中相应模板。
__constant int tOffset = 8196; // one template size in memory (in bytes)
__kernel void matchImage6( __global unsigned char* image, // pointer to the base image
            int imgWidth, // base image width
            int imgHeight, // base image height
            int imgPitch, // base image pitch (in bytes)
            int imgBpp, // base image bytes (!) per pixel
            __constant unsigned char* templates, // pointer to the array of templates
            int tWidth, // templates width (the same for all)
            int tHeight, // templates height (the same for all)
            int tPitch, // templates pitch (in bytes, the same for all)
            int tBpp, // templates bytes (!) per pixel (the same for all)
            int diff, // max allowed difference of intensity
            int maxNonmatchQt, // max number of nonmatched pixels
            __global int* result, // results
                            ) {
int x0 = (int)get_global_id(0);
int y0 = (int)get_global_id(1);
if( x0 + tWidth > imgWidth || y0 + tHeight > imgHeight)
    return;
int nonmatchQt[] = {0, 0, 0, 0, 0, 0};
for( int y = 0; y < tHeight; y++) {
    int ind = y * tPitch;
    int baseImgInd = (y0 + y) * imgPitch + x0 * imgBpp;
    for( int x = 0; x < tWidth; x++) {
        unsigned char c0 = image[baseImgInd];
        unsigned char c1 = image[baseImgInd + 1];
        unsigned char c2 = image[baseImgInd + 2];
        for( int i = 0; i < 6; i++)
            if( abs( c0 - templates[i * tOffset + ind]) > diff || 
                            abs( c1 - templates[i * tOffset + ind + 1]) > diff || 
                            abs( c2 - templates[i * tOffset + ind + 2]) > diff)
                nonmatchQt[i]++;
        ind += tBpp;
        baseImgInd += imgBpp;
    }
    if( nonmatchQt[0] > maxNonmatchQt && nonmatchQt[1] > maxNonmatchQt && nonmatchQt[2] > maxNonmatchQt && nonmatchQt[3] > maxNonmatchQt && nonmatchQt[4] > maxNonmatchQt && nonmatchQt[5] > maxNonmatchQt)
        return;
}
for( int i = 0; i < 6; i++)
    if( nonmatchQt[i] < maxNonmatchQt) {
        unsigned int pos = atom_inc( &result[0]) * 3;
        result[pos + 1] = i;
        result[pos + 2] = x0;
        result[pos + 3] = y0;
    }
}

内核运行配置: 全局工作大小 = (1900, 1200) 本地工作大小 = (32, 8) 对于 AMD 和 (32, 16) 对于 NVIDIA。

执行时间: HD 5850 - 69 毫秒, HD 6670 - 200 毫秒, GT 240 - 100 毫秒。

任何关于我的代码的评论也非常感谢。


2
这里提供的信息远远不足以回答这个问题!每一款NVidia和AMD显卡都是架构复杂的怪物,你在任何一款显卡上看到的性能很大程度上取决于代码;理解两者之间的性能差异甚至更加棘手。你能否发布你的内核和驱动程序? - Jonathan Dursi
你在内核中运行什么样的算法?内存访问模式?波前/线程块大小?需要更多信息才能提供建议。 - mfa
你要启动多少个线程?并且你是否对数组进行向量化处理? - captain
谢谢大家的回答。我明天会发布我的内核代码。 - AdelNick
等等,你是怎么测量的?只运行一次内核吗?在这种情况下,你完全受到延迟的限制。你是否发出了一系列内核调用并计时端到端运行时间? - doug65536
显示剩余3条评论
2个回答

4
执行时间的差异是由编译器造成的。您的代码可以轻松向量化。将图像和模板视为矢量类型char4的数组(每个char4矢量的第四个坐标始终为0)。而不是进行三次内存读取:
unsigned char c0 = image[baseImgInd];
unsigned char c1 = image[baseImgInd + 1];
unsigned char c2 = image[baseImgInd + 2];

只使用一个:

unsigned char4 c = image[baseImgInd];

不再使用繁琐的if语句:

    if( abs( c0 - templates[i * tOffset + ind]) > diff || 
               abs( c1 - templates[i * tOffset + ind + 1]) > diff || 
               abs( c2 - templates[i * tOffset + ind + 2]) > diff)
         nonmatchQt[i]++;

快速使用:

    unsigned char4 t = templates[i * tOffset + ind];
    nonmatchQt[i] += any(abs_diff(c,t)>diff);

因此,您可以将代码的性能提高多达3倍(如果编译器本身没有对代码进行向量化处理)。我认为AMD OpenCL编译器没有这样的向量化和其他优化。根据我的经验,NVIDIA GPU上的OpenCL通常比CUDA更快,因为它更低级别。

HD5850和HD6670 GPU都具有支持矢量化代码的架构,但AMD的编译器并不一定足够智能以进行这些转换。而Nvidia GPU使用的架构则不支持矢量化。 - chippies
你是对的。NVIDIA GPU 不需要矢量化,但 AMD GPU 需要。 - gudasergey

0

这个问题没有确切的完美答案。OpenCL 的性能取决于许多参数,如全局内存的访问次数、代码的效率等。此外,由于不同设备可能具有不同的本地、全局、常量内存,核心数量、频率、内存带宽以及硬件架构等因素,因此很难进行比较。

每种硬件都提供自己的性能提升,例如 NVIDIA 的 native_。因此,您需要更多地了解您正在使用的硬件,这可能真正起作用。但是我个人建议不要使用这样的硬件特定优化,因为它可能会影响代码的灵活性。

您还可以找到一些已发表的论文,显示 CUDA 在相同的 NVIDIA 硬件上的性能要比 OpenCL 好得多。

因此,编写提供良好灵活性的代码总是比设备特定优化更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接