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的可能性。

原文地址:https://www.cnblogs.com/mfmdaoyou/p/6685053.html