【问题标题】:My OpenCL kernel is slower on faster hardware.. But why?我的 OpenCL 内核在更快的硬件上速度较慢。但为什么呢?
【发布时间】:2011-02-06 21:57:43
【问题描述】:

当我为一个多核编程课程完成我的项目编码时,我想到了一些非常奇怪的事情,我想和你讨论一下。

我们被要求创建任何能够显着改进多核平台编程的程序。我决定尝试在 GPU 上编写代码来试用 OpenCL。我选择了矩阵卷积问题,因为我对它非常熟悉(我之前使用 open_mpi 对其进行了并行化,对大图像有很好的加速)。

就是这样,我选择了一个大的 GIF 文件 (2.5 MB) [2816X2112] 并运行顺序版本(原始代码),平均得到 15.3 秒。

然后,我在 MBP 集成 GeForce 9400M 上运行我刚刚编写的新 OpenCL 版本,平均时间为 1.26 秒。到目前为止一切顺利,速度提升了 12 倍!!

但现在我进入我的节能面板打开“图形性能模式”该模式关闭 GeForce 9400M 并打开我系统的 Geforce 9600M GT。苹果表示这张卡的速度是集成卡的两倍。

猜猜看,我使用kick-ass显卡的平均时间是3.2秒……我的9600M GT似乎比9400M慢了两倍多..

对于那些倾向于 OpenCL 的人,我会在开始之前将所有数据复制到远程缓冲区,因此实际计算不需要往返于主 ram。另外,我让 OpenCL 确定最佳的本地工作大小,因为我读到他们在计算出该参数方面做得很好。

有人知道吗?

编辑:这里有makefile的完整源代码http://www.mathieusavard.info/convolution.zip

cd gimage
make
cd ../clconvolute
make
put a large input.gif in clconvolute and run it to see results

【问题讨论】:

  • 换显卡后有没有重启电脑? AFAIK 在这些计算机上这是必需的。
  • 我注销了..当你想更换显卡时,它会强制你注销并登录+我的程序输出当前使用的显卡的名称,这样我就可以确定哪个正在运行..
  • 尝试重新启动.. 还尝试通过使用带有掩码 12X12 的 3264x2448 图像来增加问题大小,但结果相同...

标签: opencl hardware-acceleration


【解决方案1】:

9400M 集成到您的内存控制器,而 9600M GT 是一个独立的卡,通过 PCI-e 总线连接到您的内存控制器。这意味着当您将内存传输到 9400M 时,它只是将其分配到系统 RAM 中。另一方面,9600M 通过 PCI-e 将数据发送到卡上的专用图形内存。这种传输使您的基准测试看起来更慢。

如果您想比较两张显卡的性能,您应该使用 OpenCL 分析功能,而不是您当前使用的时钟功能。

cl_int clGetEventProfilingInfo (cl_event event, cl_profiling_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)

将在您将内核入队时创建的事件传递给函数,并将第二个参数传递给 CL_PROFILING_COMMAND_START 以获取内核的起点(以纳秒为单位),并将 CL_PROFILING_COMMAND_END 传递给它以获取内核的终点。确保在内核执行完成后使用此命令(事件保持其值直到超出范围。)您还可以通过将此函数应用于事件来获取将数据传输到设备所花费的时间从缓冲区的入队开始。这是一个例子:

        TRACE("Invoking the Kernel")
    cl::vector<cl::Event> matMultiplyEvent;
    cl::NDRange gIndex(32,64);
    cl::NDRange lIndex(16,16);

    err = queueList["GPU"]->enqueueNDRangeKernel(
                                                 matrixMultiplicationKernel, 
                                                 NULL, 
                                                 gIndex, 
                                                 lIndex, 
                                                 &bufferEvent,
                                                 matMultiplyEvent);
    checkErr(err, "Invoke Kernel");


    TRACE("Reading device data into array");
    err = queueList["GPU"]->enqueueReadBuffer(thirdBuff, 
                                              CL_TRUE,
                                              0,
                                              (matSize)*sizeof(float),
                                              testC,
                                              &matMultiplyEvent,
                                              bufferEvent);
    checkErr(err, "Read Buffer");
    matMultiplyEvent[0].wait();
    for (int i = 0; i < matSize; i++) {
        if (i%64 == 0) {
            std::cout << "\n";
        }
        std::cout << testC[i] << "\t";
    }
    long transferBackStart = bufferEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_START>();
    long transferBackEnd = bufferEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_END>();
    double transferBackSeconds = 1.0e-9 * (double)(transferBackEnd- transferBackStart);

    long matrixStart = matMultiplyEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_START>();
    long matrixEnd = matMultiplyEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_END>();
    double dSeconds = 1.0e-9 * (double)(matrixEnd - matrixStart);

此示例使用 C++ 包装器,但概念应该相同。

希望这会有所帮助。

【讨论】:

  • 谢谢,我会尽快测试您的建议,看看是否可以解释:P
【解决方案2】:

我得到了相同的结果,但我不确定为什么。我的内核涉及到/从的复制非常少(我为所有内核调用提供所有需要的数据,并且只返回一个 512x512 图像)。它是一个光线追踪器,因此内核工作大大超过了复制回来(400+ms 到 10ms)。尽管如此,9600M GT 还是慢了大约 1.5-2 倍。

根据 nVidia 的列表,9600M GT 应该有 32 个 SP(是 9400M 数量的两倍)。它的时钟可能也更高。

9600M GT 在某些情况下确实看起来更快,例如游戏。请参阅以下链接: http://www.videocardbenchmark.net/video_lookup.php?cpu=GeForce+9600M+GT http://www.videocardbenchmark.net/video_lookup.php?cpu=GeForce+9600M+GT

根据ars technica

此外,早期测试揭示了有关 Snow Leopard 实现的一个有趣的花絮。尽管 Snow Leopard 似乎没有为使用 NVIDIA GeForce 9400M 芯片组的机器启用双 GPU 或动态 GPU 切换(Leopard 继承了这一限制),但操作系统似乎可以同时将两者用作 OpenCL 资源。因此,即使您在 MacBook Pro 上启用了 9600M GT,如果在应用程序中遇到 OpenCL 代码,Snow Leopard 也可以发送该代码以由 9400M 中几乎处于休眠状态的 16 个 GPU 内核处理。然而,反之则不然——当运行仅启用 9400M 的 MacBook Pro 时,9600M GT 将完全关闭以节省电量,并且不能用作 OpenCL 资源。

这似乎与我们所看到的相反。此外,我一次只在一台设备上明确设置 CL 上下文。

ars forums 中有一些建议,9600M GT 也不支持双打,这可以解释这个问题。我可能会尝试编写一个综合基准来检验这个假设。

【讨论】:

    【解决方案3】:

    我在 MacBook 上测试 OpenCL 时遇到了同样的问题。我相信这是因为 GeForce 9400M 对主内存组的总线速度比 Geforce 9600M GT 更高。因此,即使 Geforce 9600M GT 比 GeForce 9400M 具有更多的功率,将内存复制到 GPU 所需的时间也太长,无法看到更强大的 GPU 对您的情况的好处。这也可能是由不适当的工作组规模造成的。

    我还发现这个网站对我的 OpenCL 体验很有帮助。

    http://www.macresearch.org/opencl

    【讨论】:

    • 感谢 Kendall,但 macresearch.org 的东西实际上是我的代码的基础:P 工作组大小是通过传入 null 参数自动设置的。
    • 尝试使用不同的尺寸。默认值并不总是最好的。
    • 好的,所以我尝试了不同的尺寸.. 两张卡上的自动检测尺寸均为 16.. 我最多可以达到 17,但它会降低两张卡上的性能.. 我收到上面的错误17. 奇怪,奇怪,奇怪......
    • 对不起,我指的是本地工作规模,而不是全球工作规模。本地的应该能够在大约 64-512 之间。
    【解决方案4】:

    性能并不是 GeForce 9400M 和 Geforce 9600M GT 之间的唯一区别。一个重要的就是一个离散 GPU。随之而来的是一系列差异,其中可能会产生影响:

    • 驱动程序批处理更多命令的趋势
    • 内存不统一。 GPU 通常只访问自己的内存,驱动程序通过 PCI-E 总线来回移动内存。

    我确定我错过了一些......

    您可以尝试以下一些想法:

    • 避免调用 clFinish。您在内存负载和执行之间调用它的方式会迫使驱动程序做不必要的工作。它会停止 GPU。
    • 分析您的代码以查看什么正在花费时间。我还不知道对 CL 性能分析的支持,但是通过您的 clFinish 调用,它通过简单地测量 CPU 端为您提供一阶估计。请注意,通常很难区分什么是延迟引起的,什么是吞吐量引起的。

    【讨论】:

    • 感谢 Bahbar,我尝试删除建议的 cl_finish 但没有成功。然后我尝试将它们全部删除(即使是不安全的),我仍然得到相同的运行时间......不过有趣的是如果我拔下计算机的电源线并让它依靠电池运行,OpenCL 运行时间会增加一倍(GeForce)。
    【解决方案5】:

    我是 OpenCL 的新手,所以我可能有点幼稚,但我怀疑您是否需要进入节能面板来切换 OpenCL 计算设备。我相信您在代码中设置 OpenCL 上下文时选择了设备。

    我的假设:1) 当您在未禁用集成 GPU 的情况下运行代码时,OpenCL 会选择您的离散 GPU 作为计算设备。您的代码在(快速)离散 GPU 上运行。 2)当您首先禁用集成 GPU 时,您将运行 OS X GUI 的负载强制到您的离散卡上。当您运行代码时,它会在独立 GPU 上运行,但会与您的 GUI 争夺资源。

    这个答案是在提出问题 11 个月后发布的,但希望它对某人有用...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多