1

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

我在 JOCL(Op​​enCL 的 Java 绑定)中编写的代码只是添加了两个二维数组(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 值。

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

再次感谢你

4

2 回答 2

0

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

于 2013-11-10T16:19:57.573 回答
0

我做了一个使用本地内存优化的矩阵矩阵乘法内核。在我的 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,这会增加占用,从而隐藏更多延迟。

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

这里:

具有 9x16x16 pblocking 算法的 HD 7870 SGEMM:1150 Gflops/s 方阵大小 = 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+z随机v+z随机值2+z 随机值3+z随机值4

代替

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

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

于 2013-11-10T17:07:36.830 回答