渲染性能相关问题
问题类型
- 流畅度
- 功耗
- 内存
抓取systrace方法
方法一:
-
运行脚本 sh 17211834804983.sh
-
执行问题复现的场景
-
将产生的trace pull到当前文件夹下并命名为trace1,命令:adb pull data/misc/perfetto-traces/trace ./trace1;
-
打开当前文件夹,命令:nautilus .;
-
将刚保存的文件./trace1在网址中打开,网址:https://ui.perfetto.dev/#;
-
也可将其转换为legacy UI,点击switch to legacy UI部分。
-
抓取的时间为10s,时间设置长了可能会存在抓不全的情况,多数用于本地自己复现问题,linux操作系统可用
-
如果抓取的trace为空的需要执行以下命令:
adb root adb shell "echo 0 > sys/kernel/tracing/tracing_on"- 抓取trace的时候不要录屏
-
方法二:
- 下载tracer文件包blog/Android性能/流畅度&卡顿掉帧/渲染/tracer.zip
- 在tracer/tracer路径下执行tracer.py 可在终端中输入python3 tracer.py —keep pftrace抓取
- 执行问题复现的场景
- ctrl+c结束trace抓取
- 在tracer/tracer/traces路径下获得.pftrace文件,将文件拖拽至https://ui.perfetto.dev/中打开解析
可以连续长时间抓取,windows和linux都可使用该方法,通常用于提供给测试同学
方法三:
使用开发者选项中的系统跟踪
- 进入开发者选项
- 系统跟踪
- 打开显示快捷设置图块
- 下拉控制中心,找到“录制跟踪记录”,点击开始,开始抓取trace,
- 滑动桌面,复现场景
- 再次点击,结束
- adb pull data/local/traces ./trace将这个文件夹上传到Jira上
在手机上即可抓取trace,通常用于提供给测试同学
打开大内存trace
卡顿问题分析
-
一帧上屏的大致流程如下:
Vsync-app信号到达,应用主线程处理 input \ animation \ traversal事件,抛任务给渲染线程,渲染线程处理绘制指令,acquireBuffer后将Buffer给到SurfaceFlinger,对应的BufferTX - com.miui.home增加,当Vsync-sf信号到,SurfaceFlinger取出队列里面的Buffer开始合成,然后执行上屏操作.

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

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

-
如何在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

-
卡顿问题分析可从三个方面着手:
首先我们看一下应用这边给的Buffer是否充足,需要关注的是BufferTX,丢帧统计在V-drop2-producer中,
接下来看SurfaceFlinger****合成是否慢,即SurfaceFlinger主线程的running时间是否长,
还需要再看一下上屏的时间是否长,即crtc_commit的时间,因surfaceFlinger和crtc_commit耗时导致的丢帧会被计算在了V-drop3-sf中
丢帧脚本新增的trace内容和表示的具体含义,请参考性能同学提供提供的文档
问题分类及总结
以下几类问题主要涉及SurfaceFlinger、display、性能模块. ,以下是总结的原因和需要继续跟进问题的模块,Jira中有详细的分析的过程和解决方案。例:【模块名-jiraID】
-
流畅度
-
应用给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是正常操作
-
SurfaceFlinger消耗Buffer不及时
-
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状态.
-
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,导致刷新频率一直没有设置成功
-
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-
上屏时间长导致的丢帧
案例分析:
【Display - HTH-385249】crtc_commit时间长导致的丢帧
-
surfacetexture视频卡顿
案例分析:
【Display - MIUIROM-1163567】切帧率导致dequeueBuffer耗时增加,在处理surfaceTexture Buffer的时候出现覆盖的情况,导致的卡顿
-
其他
多数为R和S的问题总结如下:https://wiki.n.miui.com/pages/viewpage.action?pageId=653045322
部分卡顿问题的总结如下:https://wiki.n.miui.com/pages/viewpage.action?pageId=669554137
-
功耗
该类问题需要通过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负载
-
内存
目前的内存标准,对于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中保持了引用。
”