渲染性能相关问题

问题类型

  • 流畅度
  • 功耗
  • 内存

抓取systrace方法

方法一:

  1. 运行脚本 sh 17211834804983.sh

  2. 执行问题复现的场景

  3. 将产生的trace pull到当前文件夹下并命名为trace1,命令:adb pull data/misc/perfetto-traces/trace ./trace1;

  4. 打开当前文件夹,命令:nautilus .;

  5. 将刚保存的文件./trace1在网址中打开,网址:https://ui.perfetto.dev/#;

  6. 也可将其转换为legacy UI,点击switch to legacy UI部分。

    1. 抓取的时间为10s,时间设置长了可能会存在抓不全的情况,多数用于本地自己复现问题,linux操作系统可用

    2. 如果抓取的trace为空的需要执行以下命令

      adb root
         
      adb shell "echo 0 > sys/kernel/tracing/tracing_on"
    1. 抓取trace的时候不要录屏

方法二:

  1. 下载tracer文件包blog/Android性能/流畅度&卡顿掉帧/渲染/tracer.zip
  2. 在tracer/tracer路径下执行tracer.py 可在终端中输入python3 tracer.py —keep pftrace抓取
  3. 执行问题复现的场景
  4. ctrl+c结束trace抓取
  5. 在tracer/tracer/traces路径下获得.pftrace文件,将文件拖拽至https://ui.perfetto.dev/中打开解析

可以连续长时间抓取,windows和linux都可使用该方法,通常用于提供给测试同学

方法三:

使用开发者选项中的系统跟踪

  1. 进入开发者选项
  2. 系统跟踪
  3. 打开显示快捷设置图块
  4. 下拉控制中心,找到“录制跟踪记录”,点击开始,开始抓取trace,
  5. 滑动桌面,复现场景
  6. 再次点击,结束
  7. adb pull data/local/traces ./trace将这个文件夹上传到Jira上

在手机上即可抓取trace,通常用于提供给测试同学

打开大内存trace

卡顿问题分析

  1. 一帧上屏的大致流程如下:

Vsync-app信号到达,应用主线程处理 input \ animation \ traversal事件,抛任务给渲染线程,渲染线程处理绘制指令,acquireBuffer后将Buffer给到SurfaceFlinger,对应的BufferTX - com.miui.home增加,当Vsync-sf信号到,SurfaceFlinger取出队列里面的Buffer开始合成,然后执行上屏操作.

  1. 如何查看CPU频率:

点击想看的线程所对应的运行状态,如下图所示,弹出框下面会显示其state是“Running on CPU0”

点击该“Running on CPU0”后,会直接跳转到Cpu0,看对应的“Cpu 0 Frequency”即可

  1. 如何在trace中执行SQL语句

选中搜索框,

输入法为英文,

shift+’>‘调出下面的选项,

选中Run Query

在下面的输入框中输入SQL语句,例:

select dur, name, id from slice where name like “commit %” and ts between 2151836161313 and 2152561959437

如果涉及到取时间范围,如ts between 2151836161313 and 2152561959437,这个时间的取值是start time的raw value.

一个slice块只有个start时间,我们在选取end值的时候需要选取第一个slice块 后面的任意slice块的raw value

  1. 卡顿问题分析可从三个方面着手:

首先我们看一下应用这边给的Buffer是否充足,需要关注的是BufferTX,丢帧统计在V-drop2-producer中,

接下来看SurfaceFlinger****合成是否慢,即SurfaceFlinger主线程的running时间是否长,

还需要再看一下上屏的时间是否长,即crtc_commit的时间,因surfaceFlinger和crtc_commit耗时导致的丢帧会被计算在了V-drop3-sf中

丢帧脚本新增的trace内容和表示的具体含义,请参考性能同学提供提供的文档

Atrace工具丢帧判断常见问题解答

问题分类及总结

以下几类问题主要涉及SurfaceFlinger、display、性能模块. ,以下是总结的原因和需要继续跟进问题的模块,Jira中有详细的分析的过程和解决方案。例:【模块名-jiraID】

  1. 流畅度

  2. 应用给Buffer慢导致的丢帧

案例分析:

【Performance - HTH-358887】GC操作导致renderThread线程出现texture release, running时间长,引起丢帧.

【APP - MIUIROM-1828876 / TS-107459】应用绘制操作复杂,GPU压力大,出现queueBuffer超时问题,导致Buffer过来的慢,引起丢帧.

【APP - MIUIROM-1869878】应用前几帧layout binder与systemserver通信和主线程执行的其他操作耗时,导致Buffer过来的慢,引起丢帧

【APP - MIUIROM-1937454】渲染线程renderFrame耗时长,引起丢帧

执行的绘制指令多,导致的renderFrame用时长,可通过以下方法打开开关,确认执行的操作,看是否可以优化. adb root adb shell setprop "debug.hwui.skia_atrace_enabled" true adb shell setprop "debug.hwui.skia_use_perfetto_track_events" false adb shell setprop "debug.renderengine.skia_atrace_enabled" true adb shell "setprop vendor.debug.gpu.provider meow" adb shell setprop "debug.hwui.skia_tracing_enabled" true adb shell "stop;start"

【APP - MIUIROM-1937454】AtlasTextOp耗时长,T上也有,暂时没有优化方案

【APP - MIUIROM-1789081】两帧间隔超过多个Vsync

先看一下是否切帧率(查看SurfaceFlinger进程中该值ActiveModeFPS是否变化),如果帧率正常,再看一下requestNextVsync的调用是否被阻碍

【Performance - HTH-360338】allocateBuffer binder通信耗时

应用线程前四帧在dequeueBuffer的时候allocateBuffer是正常操作

  1. SurfaceFlinger消耗Buffer不及时

  2. SurfaceFlinger主线程合成慢导致的丢帧

120Hz,如果连续多帧SF合成时间超过8.3ms,那么就会出现丢一帧的情况.如果一帧的合成时间超过20ms,就会出现连续丢帧.

要关注的点主要是SurfaceFlinger主线程 renderEngine线程,与display的binder线程等.

案例分析:

【Display - MIUIROM-1971463】与display binder通信时间长

【Performance - MIUIROM-1722261】checkLayerstack\ checkVideoLayerForSDR2HDR\ updateCompositionType\ updateBackpressureSetting\updateCompositionType这几个方法每次都会遍历所有Layer,耗时严重,部分方法为性能同学新增.

SurfaceFlinger合成慢先看一下CPU频率是否正常,如果正常和对比机对比哪部分超时,再细分析

【SF - MIUIROM-1844868 / HTH-344218】U对比T发现Layer的合成方式被修改为client,client合成会增加GPU的压力和renderEngine线程耗时长,所以需要是谁修改了合成方式.

Dump **SurfaceFlinger有这样一行log可区分出合成方式是上层修改的,**还是底层修改的

composition: DEVICE/Client

DEVICE(上层设置的合成方式,会因为圆角模糊等修改合成方式为client合成)**/**Client(底层根据策略HWC的能力修改后修改合成方式为client合成)

如果发现上面这个位置打印的合成方式有问题,需要合入下面的change

https://gerrit.odm.mioffice.cn/c/platform/hardware/qcom/display/+/473386

【Performance - HQ-356799】SurfaceFlinger主线程和renderEngine线程 runnable导致的连续丢帧

【Display - HTH-339368 / TS-82931】renderEngine线程的flush surface操作和GPU相关, 如果出现耗时长的情况, 请和高通或者MTK沟通

flush耗时 mtk回复(gl API的耗时是arm DDK中实现,这部分是老版本上旧架构的既定问题了,arm也不会有优化方案)

【Display - MIUIROM-1693464】渲染线程flushSurfaces耗时

分析:复现问题抓火焰图,找到flushSurfaces的调用栈,

auto skgpu::v1::OpsTask::onExecute(GrOpFlushState *)::(anonymous class)::operator()() const

耗时目前定位到 gsl__memory_alloc_pure_64,给高通提case

【SF-AURORA-28655 / MIUIROM-1809604 / HQ-364977】cachemiss,导致SurfaceFlinger进程renderEngine线程耗时长,出现连续丢帧的情况

因平滑圆角\模糊\阴影等使用的shader在开机启动的时候没有进行预加载,导致在滑动过程中出现cachemiss,出现连续丢帧的情况,所以需要在开机启动的时候模拟各个场景,避免在用户使用过程中出现卡顿的情况

【SF - MIUIROM-1944203 / MIUIROM-1931889 / MIUIROM-1931889 / MIUIROM-1956161】Regionsample线程runnable导致SurfaceFlinger主线程耗时长

给Regionsample线程设置VIP策略,目的是当多个prio为120的线程抢CPU资源时,优先执行Regionsample

【SF - MIUI15-5383】dequeueBuffer耗时长导致丢帧

需要关注releaseBuffer的操作,可能是因为SurfaceFlinger合成慢,还有可能是因为调到releaseBuffer某个阶段出现runnable和D状态.

  1. Vsync问题

要关注的点主要是SurfaceFlinger进程中的Vsycn-sf/ Vsync-app/ ActiveModeFPS/ VSP-mode/ VsyncWorkDuration-app /VsyncWorkDuration-sf/onComposerHalVsync线程等

案例分析:

【Display - MIUI15-5612】onComposerHalVsync(16666666)返回的是60Hz,但上层设置的是120Hz,底层返回数据有问题.导致刷新率一直没有设置成功,出现卡顿.

【Display - PIPA-4234】录制1080P 30Hz视频卡顿原因是采用了48/50Hz的刷新率,这种30Hz的视频用50Hz刷就会隔一帧出现40ms合成,中间必有一帧错过上一个Vsync,这种场景下用48/50Hz有些不合理

【Display - MIUIROM-1338994】帧率切为10Hz导致home一直没有处理input事件导致丢帧

【Display - MIUIROM-1236348】有线程设置刷新率为50Hz,导致刷新频率一直没有设置成功

  1. SurfaceFlinger未合成

要看的点是,U版本SurfaceFlinger主线程commit方法中的transactionReadyTimelineCheck,transactionReadyBufferCheck方法

案例分析:

【Display - MIUI15-14405】crtc_commit时间长,出现的isFencePending,导致SurfaceFlinger未合成,具体表现是没有执行composite

【Display - YUECHU-3688】等GPU fence,在surfaceflinger合成的时候出现Fence unsignal,导致SurfaceFlinger没有合成

需要display同事确认GPU是否正常,如果正常并且流畅度没有达标,我们这边有规避方案,挪用T版本

adb root
 
adb shell setprop debug.sf.auto_latch_unsignaled false
 
adb shell stop
 
adb shell start
  1. 上屏时间长导致的丢帧

案例分析:

【Display - HTH-385249】crtc_commit时间长导致的丢帧

  1. surfacetexture视频卡顿

案例分析:

【Display - MIUIROM-1163567】切帧率导致dequeueBuffer耗时增加,在处理surfaceTexture Buffer的时候出现覆盖的情况,导致的卡顿

  1. 其他

多数为R和S的问题总结如下:https://wiki.n.miui.com/pages/viewpage.action?pageId=653045322

部分卡顿问题的总结如下:https://wiki.n.miui.com/pages/viewpage.action?pageId=669554137

  1. 功耗

该类问题需要通过trace确认有没有新增某个线程,或者某个线程出现异常一直在running.还有就是需要和测功耗的同学确认抓取trace的时间段.确认抓trace的场景.

如果通过trace不能看出SurfaceFlinger哪部分增加了耗时,可通过SQL语句统计SurfaceFlinger进程所有线程running的时间.

参考上面”如何在trace中执行SQL语句”

# process.pid的赋值是SurfaceFlinger进程号

# ts between 204936698671 and 264995827502**,**这个时间的取值是start time的raw value.

SELECT   
  process.name AS Process,
  process.pid AS PID,
  thread.name AS Thread,
  thread.tid AS TID,
  thread_state.state AS State,  
  SUM(thread_state.dur)/1000000 AS "Wall duration (ms)",   
  AVG(thread_state.dur)/1000000 AS "Avg Wall duration (ms)",   
  COUNT(*) AS Occurrences 
FROM   
  process 
JOIN   
  thread ON process.upid = thread.upid 
JOIN   
  thread_state ON thread.utid = thread_state.utid 
WHERE   
  process.pid = 1475 
  AND State = 'Running' 
  AND  ts between 204936698671 and 264995827502  
GROUP BY   
  process.name, process.pid, thread.name, thread.tid, thread_state.state 
ORDER BY   
  process.name, process.pid, thread.name, thread.tid, thread_state.state; 

案例分析:

【SF - MIUIROM-1948500 / MIUIROM-1834821】remapBuffer导致的功耗高

dataspace发生变化不去remapBuffer,设置一个标记flag,在需要GPU合成的时候才调用remapBuffer,高通给了patch

【APP - MIUIROM-1881553 / MIUIROM-1629580】新增功能,从而导致增加GPU负载

  1. 内存

目前的内存标准,对于SurfaceFlinger内存问题主要有两个场景,一种是手机重启后静止和标准值和对比机比是否达标,还有一种场景是MTBF-monkey跑24小时后应用老化内存不达标,内存值超1G提Jira.

可参考以下文档:Native Heap/EGL mtrack

案例分析:

【APP - MIUIROM-1843852】GL mtrack值偏大

top activity 问题导致没有调用trimMemory trimCache

【SF - UPGR7325U-7832】ServiceManagerCppClient: Waited one second for SurfaceFlingerAIDL

在滑动过程中出现因平滑圆角、模糊、阴影等cachemiss导致的卡顿,进行了优化,会增加开机时间

【SF - MIUIROM-1812185 / HTH-300843】Graphic 占用的多

高通
SurfaceFlinger进程的EGL mtrack的值通常是以下几个Buffer大小的和,其他的Layer没有被统计到Surface Flinger进程的EGL mtrack
可以通过命令:adb pull /sys/kernel/debug/kgsl/proc/<pid>/mem >kgsl.txt (pid改为实际的ID)
在kgsl文件中包含有EGL mtrack所统计的信息。
其中统计为EGL mtrack信息的判断条件为usge类型为egl_image,eglsrf的类型为0。并且size需要除以eglimg的值。一般为1,有的为2。
 
总结下来一般上面统计的数据都是下面的几个layer:
 
+ name:Wallpaper#1(BLAST Consumer)1, id:86, size:36816.00KiB, w/h:3048x3048, usage: 0x10000900, req fmt:2, fourcc/mod:875709016/360287970189639681, dataspace: 0x8810000, compressed: true
  planes: R/G/B:   w/h:3048x3048, stride:12288 bytes, size:37699584
+ name:Wallpaper#0(BLAST Consumer)0, id:12, size:24480.00KiB, w/h:3048x2032, usage: 0x10000900, req fmt:2, fourcc/mod:875709016/360287970189639681, dataspace: 0x8810000, compressed: true
  planes: R/G/B:   w/h:3048x2032, stride:12288 bytes, size:25067520
+ name:FramebufferSurface, id:3, size:24480.00KiB, w/h:3048x2032, usage: 0x1b00, req fmt:1, fourcc/mod:875708993/0, dataspace: 0x88a0000, compressed: true
  planes: R/G/B/A:   w/h:3048x2032, stride:12288 bytes, size:25067520
+ name:RegionSamplingThread, id:56, size:72.00KiB, w/h:430x40, usage: 0x303, req fmt:1, fourcc/mod:875708993/0, dataspace: 0x0, compressed: false
  planes: R/G/B/A:   w/h:430x40, stride:1792 bytes, size:73728
+ name:FramebufferSurface, id:4, size:24480.00KiB, w/h:3048x2032, usage: 0x1b00, req fmt:1, fourcc/mod:875708993/0, dataspace: 0x88a0000, compressed: true
  planes: R/G/B/A:   w/h:3048x2032, stride:12288 bytes, size:25067520
+ name:FramebufferSurface, id:2, size:24480.00KiB, w/h:3048x2032, usage: 0x1b00, req fmt:1, fourcc/mod:875708993/0, dataspace: 0x88a0000, compressed: true
  planes: R/G/B/A:   w/h:3048x2032, stride:12288 bytes, size:25067520 

应用进程已负一屏为例

adb shell dumpsys meminfo com.miui.personalassistant | code - EGL_matrack的值也是42232

4个personalassistant被统计,3个passblur被统计

该机型的分辨率是3048x2032所以EGL mtrack统计的多,正常,没有出现Layer泄漏

【SF - MIUIROM-1381782】统计方式不同引起的差别

【SF - MIUIROM-1621682】mtk反馈,kernel版本不同,ION部分统计方式有区别,两个机器无可比性

【SF - MIUIROM-1827594】nativeHeap/ system的值偏大

分析工具:(文档)堆内存检视方案(Native Heap Insight)

【SF - MIUIROM-1925008】Dma buffer异常

dma的占用主要是SurfaceFlinger import的Buffer,分辨率大引起的。

【SF - HTH-338774】wallpaper在SurfaceFlinger这边import 4个Buffer,通常情况下是2个,会多出来20M左右.

原因:60Hz的帧率SurfaceFlinger会一直持有着一个Buffer,importBuffer增加

问题是google的基线就有的问题。

支持120Hz设备上,使用60Hz时,wallpaper业务层调用disconnect后,sf仍显示显示两个GraphicBuffer。

原因是一个GraphicBuffer用于上屏,另一个在numPendingBuffersToHold中保持了引用。