我要感谢Stephen在上一篇文章中的快速回复.这是本文的后续问题为什么非常简单的Renderscript在GPU中运行速度比在CPU中慢3倍
我的开发平台如下
Development OS: Windows 7 32-bit Phone: Nexus 5 Phone OS version: Android 4.4 SDK bundle: adt-bundle-windows-x86-20131030 Build-tool version: 19 SDK tool version: 22.3 Platform tool version: 19
为了评估Renderscript GPU计算的性能并掌握Renderscript使代码更快的一般技巧,我做了以下测试.
我使用标签android-4.2.2_r1.2检查了Google的Android开源项目中的代码.我之所以使用这个标签,是因为ImageProcessing测试样本在较新版本中不可用.
然后我在测试中使用了"base\tests\RenderScriptTests\ImageProcessing"下的项目.我在GPU上记录了运行代码的性能以及CPU,性能如下所示.
GPU CPU Levels Vec3 Relaxed 7.45ms 14.89ms Levels Vec4 Relaxed 6.04ms 12.85ms Levels Vec3 Full N/A 28.97ms Levels Vec4 Full N/A 35.65ml Blur radius 25 203.2ms 245.60ms Greyscale 7.16ms 11.54ms Grain 33.33ms 21.73ms Fisheye Full N/A 51.55ms Fisheye Relaxed 92.90ms 45.34ms Fisheye Approx Full N/A 51.65ms Fisheye Approx Relaxed 93.09ms 39.11ms Vignette Full N/A 44.17ms Vignette Relaxed 8.02ms 46.68ms Vignette Approx Full N/A 45.04ms Vignette Approx Relaxed 8.20ms 43.69ms Convolve 3x3 37.66ms 16.81ms Convolve 3x3 Intrinsics N/A 4.57ms ColorMatrix 5.87ms 8.26ms ColorMatrix Intrinsics N/A 2.70ms ColorMatrix Intinsics Grey N/A 2.52ms Copy 5.59ms 2.40ms CrossProcess(using LUT) N/A 5.74ms Convolve 5x5 84.25ms 46.59ms Convolve 5x5 Intrinsics N/A 9.69ms Mandelbrot N/A 50.2ms Blend Intrinsics N/A 21.80ms
表中的N/A是由完全精度或rs内在函数在GPU上运行引起的.我们可以看到,在GPU上运行的13种算法中,其中6种在GPU上运行较慢.由于此类代码是由Google编写的,因此我认为这种现象值得研究.至少,"我假设代码将在GPU上运行得更快"我从Renderscript看到并且GPU不在这里.
我调查了列表中的一些算法,我想提两个.
在Vignette中,GPU上的性能要好得多,我发现这是通过调用rs_cl.rsh中的几个函数来使用的.如果我注释掉这些功能,CPU将运行得更快(在极端情况下请参阅我之前的问题).所以问题是为什么会发生这种情况.在rs_cl.rsh中,大多数函数都是数学相关的,例如exp,log,cos等.为什么这样的函数在GPU上运行得快得多,这是因为这些函数的实现实际上是高并行的,或者仅仅因为执行在GPU上运行的版本比在CPU上运行的版本更好?
另一个例子是conv3x3和conv5x5.虽然在这个测试应用程序中还有比Google版本更聪明的实现,但我认为Google的这种实现肯定不错.它尝试最小化添加操作并使用rs_cl.rsh中的一些简化函数,例如convert_float4().所以一目了然,我认为它会在GPU上运行得更快.但是,它运行速度要慢得多(在Nexus 4和5上都使用Qualcomm的GPU).我认为这个例子非常具有代表性,因为在实现中,算法需要访问当前像素附近的像素.这种操作在许多图像处理算法中非常普遍.如果像2D卷积这样的实现在GPU中不能更快,我怀疑还有很多其他算法会遭遇同样的问题.如果您能够确定问题所在并提出一些方法来更快地制定此类算法,我们将非常感激.
更一般的问题是,根据我展示的测试结果,我想问一下人们应该遵循什么样的标准来获得更高的性能并尽可能地避免性能下降.毕竟,性能的目标是Renderscript的第二个最重要的目标,我认为RS的可移植性非常好.
谢谢!
这个问题确实有两个答案.
1:不要相信有关GPU的炒作.对于某些工作负载,它们更快.但是,对于许多工作负载而言,差异很小或是负面的.您至少有2种不同的处理器类型,不用担心使用哪种类型,只有在性能达到您想要的时候才会担心.
2:对于性能调优,我会专注于算法并避免慢速操作.例子:
当浮子提供足够的精度时,首选浮动加倍.
如果不需要IEEE-754,请使用RS_FP_RELAXED
喜欢乘法除法
使用native_*(例如:native_powr)代替精度足够的完整精度例程
在rsSample或rsGetElementAt上使用rsGetElementAt_*.在许多情况下,get的类型版本比一般获取更快,并且比rsSample快得多.
来自脚本全局变量的加载通常比来自rs_allocation的加载更快.首选内核常量的全局.
3:目前Nexus(4,5,7v2)GPU路径上的全局负载存在一些性能问题.这些将通过更新得到改进.