1. 使用DS-5 Streamline定位瓶颈
DS-5 Streamline要求GPU驱动启用性能測试,在Mali GPU驱动中激活性能測试对性能影响微不足道。
1.1 DS-5 Streamline简单介绍
可使用DS-5 Streamline从CPU和Mali GPU中实时收集性能计数器。然后以图形方式显示这些计数器。其主要功能例如以下:
• 收集计数器--从CPU和Mali GPU中
• 保存收集到的计数器数据以供回放
• 查看显示GPU活动、GPU活动和Framebuffer变化的时间线
• 以图形或表格的方式显示指定的性能计数器的值
• 观察计数器值怎样变化
• 评估每一帧的性能
• 查看处理器活动的图表
• 查看堆栈跟踪
• 查看应用程序分析(Profiling)
1.2 DS-5 Streamline分析图
1) 查看下面三个图:
• GPU Vertex activity.
• GPU Fragment activity.
• <Application processor> Instruction: Executed.
2) 分析图
• 寻找具有最高和最长图形的处理器,它的使用最多;
• 假设非常难找到占用太多时间的单个处理器。则问题可能在于带宽过度使用或图形管理被堵塞。
• 假设找到占用太多时间的处理器,则採取很多其它測量以隔离此问题;
• 假设全部图形都非常忙,则应用程序充分利用了Mali GPU。
2. 通过比較定位问题区域
能够通过下面比較来定位问题区域:
• 改动分辨率
改动分辨率,然后測试帧率变化:
假设分辨率添加。而FPS下降(即分辨率添加为原来的2倍,则FPS下降为原来的1/2),则FP或带宽是性能的瓶颈;
假设FPS不随着分辨率的变化而变化。则CPU或VP是性能的瓶颈。
• 改变纹理大小
逐步减小纹理的大小,假设帧率添加,且纹理Cache命中率太低:则表明纹理太大。带宽是性能的瓶颈。
• 降低Shader的长度
假设Shader太长。它将降低帧率,深度缩短Shader并进行測试。
注:假设分辨率或FPS加倍,则FP可得到的cycles减半。
• 使用空的Fragment Shder
一个null shader什么都不做。
假设使用null shader,性能高速上升。则表明Fragment Shader或带宽是性能瓶颈。
• 改变顶点数
假设降低顶点数。则FPS上升,则表明顶点数过多或带宽是性能瓶颈。
• 改变纹理位深度
当降低纹理深度时,假设FPS上升,则表明内存带宽是性能的瓶颈。
• 改变Drawing Surface位深度
当降低surface位深度,假设FPS上升。则表明内存带宽是性能的瓶颈。
• 降低draw调用
优化应用程序以降低draw调用,观察性能变化。
• 降低状态变化
优化应用程序以降低状态变化,观察性能变化。
3. 隔离详细的问题区域
其方法例如以下:
3.1 应用处理器(CPU)限制了应用性能
• 应用逻辑复杂导致性能问题
假设删除draw调用和eglSwapBuffers之后。性能变化非常少或没有变化,则表明瓶颈在应用逻辑,可通过OProfile来进行分析。它可区分用户态和Kernel态瓶颈问题。
• 驱动超负荷导致性能问题
假设低分辨率输出表明瓶颈在于CPU。且应用逻辑没有问题。则问题可能在于调用OpenGL ES API的方式:
1) 太多的draw调用
2) 太多的状态变化
3) 管道被堵塞
• 应用程序逻辑与驱动超负荷共同导致了性能问题
可通过DS-5或OProfile分析问题的根源所在。
3.2 顶点处理器(VP)限制了应用性能
假设顶点处理器限制了应用性能,问题可能在于下面方面:
• 太多的顶点
• Vertex Shader太长
• Vertex SHader太复杂
• 三角形设置时间过长
• 多边形列生成器单元时间过长(PLBU: Polygon List Builder Unit)
3.3 像素处理器(FP)限制了应用性能
假设像素处理器(FP)限制了应用性能,则问题可能在下面方面
1) 瓶颈:像素处理器(Fragment Processing)
• 过多的draw调用
• 须要读取太多的纹理
• 纹理cache miss过高
2) 瓶颈:像素处理程序(Fragment Shding)
• Shader太长
• Shader太复杂
• Shader太长且太慢
• Shader分支太多
3.4 内存带宽限制了应用性能
内存带宽影响一切且非常难直接測量。假设一个处理器限制了性能。其它优化没有不论什么效果,则可能量内存带宽导致了此问题。其原因在于:
• 纹理过多或过大
• 太多的draw调用
4. 优化工作总流程
总的优化工作流程例如以下图所看到的:
首先相应用进行性能測试。以决定瓶颈所在的区域(CPU、VP、FP或内存带宽)。
• 必须在具有Mali GPU的真实的硬件上測试
• 使用DS-5 Streamline,并观察下面三个值:
1) GPU Vertex activity
2) GPU Fragment activity
3) <Application processor: CPU> Instruction: Executed
比較以上三个,找到占用时间最长且最高的图。
• 判定问题所在的区域
1) 假设能找到占用时间最长且最高的图,则问题可能出在这里
2) 假设不能看出某个处理器特别忙。但能够看到不同处理器间存在间隙,则可能管道被API堵塞了。问题在于CPU
3) 假设以上两种情况都不存在,则问题可能在于带宽问题
5. 应用处理器(CPU)优化工作流程
总的CPU优化工作流程例如以下图所看到的:
5.1 Applicatoin bound
假设应用时间太高(DS-5 Streamline中查看相应的应用进程)。应用程序可能导致性能问题,由于它不能足够快地产生命令。
5.2 API bound
假设驱动时间太高(DS-5 Streanline中查看Kernel进程)。驱动可能导致性能问题,由于它不能产生足够的命令。典型的原因是:没有以优化的方式调用OpenGL ES API函数,应用调用了太多的OpenGL ES API函数。
5.3 检查是否太多的draw调用?
counter查看此值:
1) glDrawElements Statistics: Calls to glDrawElements
2) glDrawArrays Statistics: Calls to glDrawArrays
5.4 检查是否使用了VBO?
怎样不使用VBO,每一帧都必须数据传输,这将限制应用的性能。
在Utgard架构的Mali GPU中,可通过下面counter測量其使用情况:
1) BufferProfiling: VBO Upload Time (ms)
假设以上counter在出现尖峰的几帧之后,变为了0或值非常小有一帧或多帧,表明你可能正确地使用了VBO;假设以上counter一直为0或非常小。表明没有足够地或根本没有使用VBO。
5.5 检查是否有管道堵塞?
确认CPU和GPU是否同一时候忙,假设不是,则管道可能被堵塞了。为了避免管道堵塞。避免调用下面OpenGL ES函数:
• glReadPixels()
• glCopyTexImage()
• glTexSubImage()
5.6 检查是否有太多的状态变化?
状态变化开销相对较大,太多状态变化可能使用driver超负荷执行,从而影响性能。可通过查看下面OpenGL ES API的调用情况来查看状态变化:
• glEnable()
• glDisable()
6. GPU(Utgard)优化工作流程
6.1 顶点处理(VP)限制性能
注:在实际应用中,顶点处理(Vertex Processing)非常少成为性能瓶颈。
高的顶点处理时间工作流程例如以下图所看到的:
6.1.1 检查vertex shader时间是否高?
是否总是高来确定存在此问题:
• Mali GPU Vertex Processor: Active cycles, vertex shader
为了查找其真正的原因,可分析下面三个counter来确定:
• Mali GPU Vertex Processor: Active cycles
• Mali GPU Vertex Processor: Active cycles, vertex shader
• Mali GPU Vertex Processor: Vertex loader cache misses
1) Shader太长?
假设下面条件都为真,表明Shader太长。须要缩短它。
• Active cycles vertex shader < Active cycles
• Vertex loader Cache misses值过高
2) Shader太复杂?
假设下面条件都为真。则表明Shader太复杂:
• Active cycles vertex shader接近Active cycles
• Vertex loader Cache misses值为低
可採用下面方法解决此问题:
• 简化Shader
• 应用算术优化
• 考虑是否可把部分工作移到CPU或FP(Fragment Processor)
3) Shader有太多的分支?
Mail GPU中的分支代价相对较低,可是太多的分析将导致Shader太长或太复杂。
6.1.2 检查顶点是否太多?
可查看下面counter的图形是否总是高来确定此问题。
•Mali GPU Vertex Processor: Vertices processed
6.1.3 检查创建多边形列表(PLBU)时间是否高?
可通过測量下面counter的值来确定Polygon List Builder Unit (PLBU)时间是否为高:
• Mali GPU Vertex Processor: Active cycles, PLBU geometry processing
假设以上counter图形总是高,则应用可能使用了太多的三角形。降低三角形数量的方法例如以下:
• 使用更少的对象(Use fewer objects)
• 使用简单的对象(Use simpler objects)
• 删除镶嵌的对象(De-tessellate objects)
• 裁剪掉一些三角形(Cull triangles)
6.1.4 检查被裁剪掉(culled)的原语
可通过下面counter查看被裁剪掉的原语:
• Mali GPU Vertex Processor: Primitives culled
假设“Primitives culled”的图形低,表明应用没有使用足够的裁剪。确认“backface culling”和“depth testing”都被激活。
假设“Primitives culled”的图形高,可能有下面几方面的原因:
• 应用可能使用了太多的三角形
• 应用可能没有使用视锥裁剪
• 应用可能让Mali GPU做了太多的裁剪
6.1.5 检查是否使用了VBO?
參考本文5.4。
6.2 像素处理(FP)限制性能
像素处理器的瓶颈来源于下面双方面:
1) 纹理带宽高
2) Fragment Shader程序长
高的像素处理时间优化流程例如以下图所看到的:
6.2.1 纹理带宽高
6.2.1.1 检查纹理带宽
測量下面counters:
• Fragment Processor: Total bus reads
• Fragment Processor: Texture descriptors reads
假设以上两个counters的图形都低,则瓶颈在于Fragment Shader。
假设以上两个counters的图形都高,则瓶颈在于纹理。
6.2.1.2 检查超大的纹理
检測下面counters:
• Mali GPU Fragment Processor X: Texture cache hit count.
• Mali GPU Fragment Processor X: Texture cache miss count.
纹理cache脱靶率一般是纹理cache命中率的10%,假设高于此值,可能存在下面问题:
1) 纹理太大
2) 纹理位深度太高
3) 应用没有使用mipmapping
假设以上随意条件为真,则应用可能存在内存带宽问题。
6.2.1.3 检查压缩纹理读取
測量下面counters:
• Mali GPU Fragment Processor X: Texture cache hit count (CountA)
• Mali GPU Fragment Processor X: Compressed texture cache hit count (CountB)
针对以上两个counters比較分析例如以下:
1) 假设CountB是0,则没有使用压缩纹理
2) CountA-CountB(即未压缩纹理数)远远小于CountB。则表明使用的压缩纹理太少,能够考虑使用很多其它的压缩纹理
3) 假设压缩纹理的数量远远大于未压缩纹理的数量,则问题可能在于:
• 纹理太大
• 应用没有使用mipmapping
• 纹理太多
纹理使用大量的内存带宽,这可能导致shader不能获取到足够的数据。从而导致性能降低。
6.2.1.4 检查overdraw
检測下面counter:
• Mali GPU Fragment Processor X: Fragment passed z/stensil count (count)
overdraw factor = count/屏幕像素数(1920x1080);
1) 假设factor等于1。表明没有overdraw,但此情况一般非常少,其通常为2.5,但依赖详细应用
2) 假设factor大于2.5。则性能将被影响,可使用下面技术减小overdraw:
• 启用深度測试
• 启用“back face culling”以避免渲染不可见的面
• 依照深度排序场景中的对象
• 从前到后的顺序画非透明对象
• 从后到前的顺序画透明对象
6.2.2 Fragment Shader程序长
高的Fragment Shader时间优化流程例如以下:
6.2.2.1 确认问题在Fragment Shader
測试下面counters:
• Mali GPU Fragment Processor X: Fragment passed z/stensil count. (CountA)
• Mali GPU Fragment Processor X: Instruction completed count.(CountB)
CountB/CountA:其结果为每一个Fragment花费的平均指令数。假设此值高,它表明应用程序有较高的fragment shader time。其參考值參见:怎样计算Fragment Shader的最大cycles
6.2.2.2 检查shader是否太长?
測量下面的硬件counters:
• Mali GPU Fragment Processor X: Program cache miss count. (CountA)
• Mali GPU Fragment Processor X: Program cache hit count. (CountB)
通常CountA是非常低的,且不大于CountB的0.01%。
假设CountA图形高。表明Fragment Shader程序太长。须要缩短shader程序并验证。
6.2.2.3 检查shader是否太复杂?
測量下面的硬件counters:
• Mali GPU Fragment Processor X: Program cache miss count. (CountA)
• Mali GPU Fragment Processor X: Program cache hit count. (CountB)
通常CountA是非常低的。且不大于CountB的0.01%。假设CountA图形非常低,表明Fragment Shader太复杂。须要尝试下面方法:
1) 简化shader
2) 算法优化
3) 考虑是否可把ahder的部分功能移动CPU或VP
再次验证。假设对改善性能仍然无效,则看看是否shader太长且太复杂。
6.2.2.4 检查shader是否太长且太复杂?
对些。须要简化shader程序且缩短shader长度。
6.2.2.5 检查是否太多分支?
測量下面硬件counters:
• Mali GPU Fragment Processor X: Pipeline bubbles cycle count (CountA)
假设CountA高。表明shader可能有太多分支。
注:在Mali GPU上。分支不是一个大问题,因的它的计算量相对较小。
6.3 带宽限制性能
本节介绍怎样确认带宽限制了性能。及怎样降低带宽使用。
带宽限制工作流程例如以下图所看到的:
6.3.1 測试纹理cache命中与脱靶比率
測量下面的FP硬件counters:
• Mali GPU Fragment Processor X: Texture cache hit count. (CountA)
• Mali GPU Fragment Processor X: Texture cache miss count.(CountB)
通常CountA/CountB接近10,此比率越高越好,越低越糟糕。
一个低的比率表明cache使用高于正常状态,其原因可能为:
1) 使用了太大的纹理
2) 使用了太多的大纹理
3) 应用没有使用压缩纹理
4) 应用没有使用mipmap纹理
假设应用存在以上问题,则先进行了解决之后。再进行測试。
6.3.2 检查位块传输
位块传输(blitting)使用内存带宽且可能导致带宽过度使用。可查看下面counter:
• Mali EGL Software Counters: Blit Time
假设系统传输一个高分辨率的framebuffer。每秒的带宽须要几百MB。
假设系统设置不对,可能发生位块传输。
注:位块传输可能是显示系统的一部分,假设这样,位块传输是无法避免的。
6.3.3 測量可用最大带宽
为了定位谁过度使用了带宽:
• 计算出可得到的最大带宽
• 与系统的各个部分进行比較,以找到谁过度使用了带宽
假设不清楚设备的最大可用带宽,可使用一个測试程序来測量带宽,測试程序应满足下面要求:
• The highest resolution available.
• Highest bit depth possible.
• Very large, high bit depth textures.
• 16x Anti-aliasing.
• No texture compression.
• No mipmapping.
• No VSYNC.
假设測试程序执行帧率低。表明它充分使用了内存带宽。当执行測试程序时。測量下面counters:
• Mali GPU Vertex Processor: Words read, system bus.
• Mali GPU Vertex Processor: Words written, system bus.
• Mali GPU Fragment Processor X: Total bus reads.
• Mali GPU Fragment Processor X: Total bus writes.
注:假设Mali GPU有多个Fragment Processors,则须要測试每一个FP。
把以上全部的測试结果加起来,然后乘以8。此结果为每秒可用的最大带宽,其单位为MB(Megabytes)。此结果包含cache使用,它可能稍稍大于系统中真正可用的最大内存带宽。
6.3.4 比較应用带宽与最大可用带宽
执行应用程序并測量下面counters:
• Mali GPU Vertex Processor: Words read, system bus.
• Mali GPU Vertex Processor: Words written, system bus.
• Mali GPU Fragment Processor X: Total bus reads.
• Mali GPU Fragment Processor X: Total bus writes.
把以上结果加起来并乘以8。其结果为应用程序使用的总带宽。其单位为MB/s。然后与6.3.3中的最大值进行比較,假设比較接近。说明应用使用了大多的内存带宽。
比較这些值。年谁最高:
1) 假设Mali GPU FP使用了太多的带宽,见下面的FP带宽限制性能
2) 假设Mali GPU VP使用了太多的带宽,见下面的VP带宽限制性能
6.3.5 FP带宽限制性能
假设应用的性能被FP带宽限制了。问题可能在于下面几方面:
• 纹理
通常读取纹理占用大量内存带宽。可降低纹理带宽的方法例如以下:
1) 减小纹理数量
2) 降低纹理分辨率
3) 降低纹理位深度
4) 使用mipmapping
5) 使用压缩纹理
• Overdraw
当像素被绘制在彼此之上,overdraw就发生了。它浪费了带宽,由于被绘制在其上的像素是不可见的。
• Trilinear filtering
三线性过滤须要读取多个纹理生成一个单一的象素。它使用了大量的带宽。
• Fragment Shader太复杂
复杂的Shaders拥有大量的中间状态,这些中间状态可能占满了cache内存。从而导致把中间状态刷新到主内存中。
6.3.6 VP带宽限制性能
假设VP过度占用带宽导致了性能问题。则问题可能在于:
• 太多的三角形
太多的三角形将占用大量带宽,但一般不会发生,除非场景调试复杂
假设不使用culling,也可能占用大量带宽。由于VP将处理一些从不被绘制的三角形
• 顶点Shader太复杂
复杂的Shaders拥有大量的中间状态,这些中间状态可能占满了cache内存。从而导致把中间状态刷新到主内存中。
• 读取非本地数据
假设你把从不使用的数据传递给GPU并cache起来。
避免使用稀疏的顶点数组,总是把数据放在一起以提高cache的可能性。