11

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

我们被要求创建任何在为多核平台编程时会显示出显着改进的程序。我决定尝试在 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
4

5 回答 5

10

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++ 包装器,但概念应该相同。

希望这可以帮助。

于 2010-11-29T02:46:41.537 回答
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论坛中有一些建议说9600M GT也不支持双打,这可以解释这个问题。我可能会尝试编写一个综合基准来测试这个假设。

于 2010-05-19T15:21:28.103 回答
1

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

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

http://www.macresearch.org/opencl

于 2010-04-12T13:38:47.980 回答
1

性能并不是 GeForce 9400M 和 Geforce 9600M GT 之间的唯一区别。一个很大的问题是一个独立的GPU。随之而来的是一系列差异,其中以下可能会产生影响:

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

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

这里有一堆你可以尝试的想法:

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

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

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

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

于 2011-03-10T08:24:42.467 回答