Mali GPU OpenGL ES 应用性能优化--测试+定位+优化流程

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调用?

通常上千的draw调用将导致性能严重下降,一般每帧在保持在1000次以内的draw调用较佳。使用DS-5 Streamline中的以下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时间是否高?

可查看以下counter的图形是否总是高来确定存在此问题:

? 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程序可能又长又复杂。对些,需要简化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的可能性。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 20:26:42

Mali GPU OpenGL ES 应用性能优化--测试+定位+优化流程的相关文章

Mali GPU OpenGL ES 应用性能优化--基本方法

1. 常用优化工具 2. 常用优化方案 OpenGL ES优化的主要工作是在图形管道中找到影响性能的bottleneck,其bottleneck一般表现在以下几方面: ? 在应用程序代码中,如冲突检测     ? GPU与主内存间的数据传输     ? 在VP(Vertex Processor)中的顶点处理     ? 在FP(Fragment Processor)中的片断处理 可通过DS-5 Streamline来定位性能瓶颈(Locate bottleneck).为了获取更好的性能,可从以下

OpenGL ES 中的模板测试

模板测试的主要功能是丢弃一部分片元,相对于深度检测来说,模板测试提出的片元数量相对较少.模板测试发生在剪裁测试之后,深度测试之前. 使用模板测试时很重要的代码提示: 1 1.glClear( GL_STENCIL_BUFFER_BIT); 2 //启用模板测试 3 2.glEnable(GL_STENCIL_TEST); 大多数情况你的模板遮罩(stencil mask)写为0x00或0xFF就行. 1 // 0xFF == 0b11111111,此时,模板值与它进行按位与运算结果是模板值,模板

OpenGL ES 2.0 剪裁测试

剪裁测试:可以在渲染时用来限制绘制区域,通过此技术可以在屏幕(帧缓冲)上指定一个矩形区域. //启用剪裁测试 GLES20.glEnable(GL10.GL_SCISSOR_TEST); //设置区域 GLES20.glScissor(0,480,230,200); //禁用剪裁测试 GLES20.glDisable(GL10.GL_SCISSOR_TEST); Alpha测试:当绘制一个片元时,首先检测其Alpha值,若Alpha值满足要求,则通过测试,绘制此片元,负责丢弃此片元,不进行绘制.

[转] iOS OpenGL ES Guide

OpenGL ES 小结 概述 OpenGL ES (Open Graphics Library for Embedded Systems)是访问类似 iPhone 和 iPad 的现代嵌入式系统的 2D 和 3D 图形加速硬件的标准. 把程序提供的几何数据转换为屏幕上的图像的过程叫做渲染. GPU 控制的缓存是高效渲染的关键.容纳几何数据的缓存定义了要渲染的点.线段和三角形. OpenGL ES 3D 的默认坐标系.顶点和矢量为几何数据的描述提供了数学基础. 渲染的结果通常保存在帧缓存中.有两

OpenGL ES Emulator比较

http://blog.csdn.net/nhsoft/article/details/6337434 http://www.klayge.org/2011/04/20/opengl-es-emulator横向比较/ http://blog.csdn.net/nhsoft/article/details/6337434 ============================================================================ 目前我手边可选的Emul

Chapter 1 : OpenGLES 3.0 简介 (2)—— OpenGL ES 3.0

管道 如前所属,本书讲解的API版本是OpenGL ES 3.0.本书的目标是,深入讲解OpenGL ES 3.0的技术细节,给出具体的例子来说明如何使用某个特性,并且讨论了各种性能优化技术.当您读完这本书,您应该可以对OpenGL ES 3.0API有一个很好的把握.您将可以轻松的写出让人新服的OpenGL ES 3.0的应用程序,并且您不必通过阅读多种OpenGL ES的规范来搞懂某个特性是如何工作的. OpenGL ES 3.0实现了可编程着色图形管道.OpenGL ES 3.0规范包含两

OpenGL ES 3.0 支持的设备和模拟器

最近自己写的引擎想要做OpenGL ES 3.0,因为现在市场大部分是是 OpenGL ES 2.0,首先要找一个支持OpenGL ES 3.0的设备或者模拟器,所以顺带着对市面上支持的设备做了一些调查. 1.支持OpenGL ES 3.0设备 IOS从IOS7以上版本开始支持ES 3.0 *IOS                             GPU                                       CPU (1) iphone 5s            

OpenGL ES 2.0基本概念

1. OpenGL ES 2.0可编程管道 OpenGL负责把三维空间中的对象通过投影.光栅化转换为二维图像,然后呈现到屏幕上. 上图黄色部分(Vertex Shader和Fragment Shader)为此管道的可编程部分.整个管道包含以下两个规范: 1) OpenGL ES 2.0 API specification 2) OpenGL ES Shading Language Specification (OpenGL ES SL) 详细流程图如下: 此流程把三维数据变换为可以显示的二维数据

OpenGL ES 3.0片段着色器(四)

片段着色器流程图 片段着色器(fragment shader)实现了一个通用的可编程操作片段的方法.片段着色器执行由 光栅化生成的每个片段. • Shader program(着色器程序)—片段着色器程序源码或描述将在该片段上可以执行的操作. • Input variables(输入变量)—光栅化阶段使用插补技术为片段着色器产生顶点着色器的输出 • Uniforms—片段着色器的常量数据 • Samplers—Uniforms使用的具体类型,在纹理(Texture)中被片段着色器使用 片段着色可