【问题标题】:Array Sum Benchmark on GPU - Odd Results?GPU 上的数组和基准测试 - 奇怪的结果?
【发布时间】:2013-11-22 06:27:18
【问题描述】:

我目前正在 AMD Radeon HD 7870 上使用 OpenCL 进行一些基准测试。

我在 JOCL(Op​​enCL 的 Java 绑定)中编写的代码只是添加了两个 2D 数组(z= x + y),但它做了很多次(z=x+y+y+y+y+y +y...)。

我添加的两个数组的大小是 500 x 501,我正在循环遍历我想在 GPU 上将它们添加在一起的迭代次数。所以我首先添加它们一次,然后添加十次,然后添加一千次,等等。

我循环到的最大迭代次数是 100,000,000。下面是我运行代码时日志文件的样子(计数器是我的程序在 5 秒内执行的次数):

Number of Iterations: 1
Counter: 87
FLOPS Rate: 0.0043310947 GFLOPs/s

Number of Iterations: 10
Counter: 88
FLOPS Rate: 0.043691948 GFLOPs/s

Number of Iterations: 100
Counter: 84
FLOPS Rate: 0.41841218 GFLOPs/s 

Number of Iterations: 1000
Counter: 71
FLOPS Rate: 3.5104263 GFLOPs/s

Number of Iterations: 10000
Counter: 8
FLOPS Rate: 3.8689642 GFLOPs/s

Number of Iterations: 100000
Counter: 62
FLOPS Rate: 309.70895 GFLOPs/s

Number of Iterations: 1000000
Counter: 17
FLOPS Rate: 832.0814 GFLOPs/s

Number of Iterations: 10000000
Counter: 2
FLOPS Rate: 974.4635 GFLOPs/s

Number of Iterations: 100000000
Counter: 1
FLOPS Rate: 893.7945 GFLOPs/s

这些数字有意义吗?我觉得 0.97 TeraFLOPS 相当高,我一定是错误地计算了 FLOP 的数量。

另外,我相信我计算的 FLOP 数量应该随着迭代次数的增加而趋于平稳,但这在这里并不那么明显。看来如果我继续增加迭代次数,计算出来的 FLOPS 也会增加,这也让我相信我做错了什么。

仅供参考,我按以下方式计算 FLOPS:

FLOPS = 计数器(500)(501)(迭代)/(time_elapsed)

对于这个问题的任何帮助将不胜感激。

谢谢

编辑:

我现在已经在一系列迭代(我将 y 与 x 相加的次数)以及数组大小上进行了相同的基准测试。我已经生成了以下曲面图,可以在这个 GitHub 存储库中看到

https://github.com/ke0m/Senior_Design/blob/master/JOCL/Graphing/GoodGPUPlot.PNG

我在这个情节上询问了其他人的意见,他们向我提到,虽然我计算的数字是可行的,但它们是人为的高。他们说这在情节的陡坡中很明显,这并没有任何物理意义。关于为什么斜率如此陡峭的一个建议想法是因为编译器将控制迭代(int 类型)的变量转换为 short,因此强制该数字保持在 32000(大约)以下。这意味着我在 GPU 上做的工作比我认为的要少,而且计算的 GFLOPS 值更高。

任何人都可以证实这个想法或提供任何其他想法来解释为什么情节看起来如此吗?

再次感谢您

【问题讨论】:

    标签: arrays opencl benchmarking gpu jocl


    【解决方案1】:

    counter(500)(501)(iterations) - 如果这是用整数计算的,结果可能对于整数寄存器来说太大了。如果是这样,在计算之前转换为浮点数。

    【讨论】:

      【解决方案2】:

      我做了一个使用本地内存优化的矩阵-矩阵乘法内核。在我的 HD7870 @ stock 设置上,它每秒只进行大约 5000 亿次求和和 5000 亿次乘法运算,这相当于 1 Teraflops。如果您的卡也处于库存设置,这与您的计算非常接近。

      是的,您的计算是有意义的,因为 gpu 的峰值约为 2.5 Tflops/s,并且您正在本地内存/寄存器空间中进行计算,这需要接近卡的峰值。

      您只做加法,所以每次迭代只需加 1(不做任何乘法,我假设每个核心有一个管道是空的,所以您有近一半的峰值)。

      每 a=b+c 1 次失败

      所以你对翻牌价值的看法是正确的。

      但是,当您不给 gpu 一个“总项目数的共振条件”,例如 512(最大本地项目大小的倍数)或 256 或 1280(核心数)的倍数时,您的 gpu 将无法完全有效地计算并且会降低小型阵列的性能。

      此外,如果您没有提供足够的总扭曲,线程将无法像在 1,10,100 次迭代中那样隐藏主内存的延迟。隐藏内存延迟需要计算单元上的多个扭曲,以便所有 ALU 和 ADDR 单元(我的意思是所有管道)大部分时间都被占用。占用在这里非常重要,因为每个内存操作的操作很少。如果您将工作组大小从 256 减少到 64,这可能会增加占用,从而隐藏更多延迟。

      反复试验可以为您提供最佳的峰值性能。否则,您的内核会因主内存带宽和线程启动/停止延迟而成为瓶颈。

      这里:

      HD 7870 SGEMM with 9x16x16 pblocking algorithm: 1150 Gflops/s for square matrix size=8208

      此外,除法和特殊功能可以被视为每个项目 50 到 200 次失败,并受制于它们的不同版本(如软件 rsqrt() 与硬件 rsqrt() 近似)。

      尝试使用 256 倍数的数组大小和 1M 等高迭代次数,并尝试将 64 或 128 作为每个计算单元的本地项。如果您可以同时将它们相乘,则可以达到更高的触发器吞吐量。您也可以将 y 与 2 或 3 相乘以使用乘法管道!这样你可能会获得比以前更高的失败率。

      x=y+z*2.0f+z*3.0f+z*4.0f+z*5.0f ---->8 次失败

      或反对编译器的自动优化,

      x=y+zrandomv+zrandomval2+zrandomval3+zrandomval4

      而不是

      x=y+z+z+z+z ----->4 次失败

      编辑:我不知道 HD7870 是否使用不同的(额外的一批)ALU 进行双精度(64 位 fp)操作,如果是,那么您可以使用它们进行混合精度操作以获得 %10 以上触发器吞吐量,因为 HD7870 能够以 32 位速度的 1/8 的 64 位速度运行!你可以用这种方式让你的卡爆炸。

      【讨论】:

        猜你喜欢
        • 2012-06-27
        • 1970-01-01
        • 2015-10-21
        • 1970-01-01
        • 1970-01-01
        • 2011-12-26
        • 1970-01-01
        • 2014-04-13
        • 1970-01-01
        相关资源
        最近更新 更多