使用Mali Graphics Debugger调优Unity程序(Killer示例)

What is MGD

ARM® Mali™ Graphics Debugger的作用之一是针对采用ARM® Mali™ GPU的Android手机,进行app的GPU运行时调试和调优。

Why MGD

本文MGD主要用于性能调优。

关于GPU性能调优,定性不定量都是耍流氓。
猜是虚的、打嘴炮讨论是无用的、运行时正则表达式disable对象是盲目的、Unity Profiler是难于真机调试的、GPA(Intel® Graphics Performance Analyzers)是不同平台的、Unity FrameDebugger是从实现本质决定了不能定量到高于DrawCall精度的。

另外,本文假设已确定瓶颈出现在GPU。否则,应优先调优CPU性能。直接使用Unity真机调试是不错的CPU性能调优手段。

Doc & Setup

阅读[ARM® Mali™ Graphics Debugger User Guide](http://malideveloper.arm.com/downloads/tools/mgd/1.3.2/Mali Graphics Debugger v1.3.2 User Guide.pdf)是了解MGD最全面的途径,里面包括了如何设置MGD和使用MGD。
由于MGD里会直接出现大量OpenGL/OpenGL ES的API,所以也可按需查阅AW OpenGL ES 3.0 Programming Guide 2nd Edition

本文以MGDv2.1版本为基础进行编写。编写完毕后数天(约2015-08-11)得知MGDv3.0已发布,其改进了体验和UI框架、FrameBuffer View、支持MRT/DepthBuffer/StencilBuffer的截取、更好的截取性能和截取文件大小优化。详情可参考官网或[Mali Graphics Debugger 3.0.0 User Guide](http://malideveloper.arm.com/downloads/tools/mgd/3.0/Mali Graphics Debugger v3.0.0 User Guide.pdf)。

关于MGD设置,本文为了内容完整性也精简地描述如下。(你若已设置好或暂不关心设置,也可跳过以下设置步骤,直接阅读下面的操作步骤、思考过程和发现killer的问题及其以下章节。)

  • 在电脑装好MGD
  • 准备好Mali GPU的Android手机。基于Mali的设备不少,比如Samsung Galaxy S3等基于Exynos SoC的手机。具体列表见Mali SoC implementation
  • 本文用已Root的Android的设备进行。但未Root也可用,但需要参考上面User Guide,以另外的方式进行。
  • 在电脑上安装好ADB(Android Debug Bridge),并且把ADB设置到操作系统(windows or OSX)的环境变量中。
  • 连接Android设备和电脑。
  • 打开命令行,输入:
#拷贝mgd版OpenGL ES运行时库和mgd后台进程到手机sdcard文件夹
cd /your_computer/path_of_installed_mgd

adb push libGLES_mgd.so /sdcard/
adb push mgddaemon /sdcard/

#准备进入手机进行命令行操作
adb shell
#以下命令在手机中执行
su
#拷贝mgd版OpenGL ES库和mgd后台进程到手机system文件夹并且修改为可执行权限
cd /sdcard/cp mgddaemon /system/bin/mgddaemon
chmod 777 /system/bin/mgddaemon
cp libGLES_mgd.so /system/lib/egl/libGLES_mgd.so
chmod 777 /system/lib/egl/libGLES_mgd.so

#Android 4.2 和 4.3切换到mgd版OpenGL ES运行时库:改egl.cfg配置方式
cp /system/lib/egl/egl.cfg /system/lib/egl/egl.cfg.bak
echo "0 0 mgd" > /system/lib/egl/egl.cfg

#Android 4.4 and 5.0切换到mgd版OpenGL ES运行时库:文件链接方式
cd /system/lib/egl
ln -s libGLES_mgd.so libGLES.so
ln -s libGLES_mgd.so libEGL_mgd.so
ln -s libGLES_mgd.so libGLESv2_mgd.so
ln -s libGLES_mgd.so libGLESv1_CM_mgd.so

#设置mgddaemon,叫它只调试com.tencent.killer这个进程。这里应填入你自己的进程id
echo "com.tencent.killer" > /system/lib/egl/processlist.cfg

#先退回到电脑,可能不止一次exit
exit

#准备打通调试信息转发通道
adb forward tcp:5002 tcp:5002

#再次进入手机,启动mgd后台进程
adb shell
su
mgddaemon
  • 在电脑上打开MGD,如下图点击Connect按钮


    点击Connect按钮,连接MGD和设备
  • 运行killer(或你自己的app)
  • MGD成功自动收集killer的GPU运行时调试信息
MGD成功自动收集killer的GPU运行时调试信息

至此,Setup操作已完毕。接下来,需要保持手机和电脑的USB连接,进行进一步的调试调优操作,亦可用通过菜单将当前调试数据保存到电脑。

操作步骤、思考过程和发现killer的问题

关于killer

killer(产品名字《独立防线》)为我们项目组一款基于Unity的可FPS/TPS切换、可PVP/PVE的3D射击游戏。

第一帧:主角第三人称状态,未露出FPS状态精细武器、无特效

在游戏中操作,进入战斗。并保持主角在主角第三人称状态,未露出FPS状态精细武器、无特效——一个最纯粹的战斗情况。

保持主角在主角第三人称状态,未露出FPS状态精细武器、无特效

从上图发现MGD已自动收集GPU数据,很是烦人,此时,可点击暂停按钮,暂停游戏,从而暂停收集。

点击Toggle Fragment Count按钮(注意之前的操作步骤如并非MGD和设备先Connect好了之后才运行app,可能会导致本按钮无法点击),再点击下一帧,可用收集下一帧的Fragment Shader的信息。这是因为Fragment Shader往往是性能消耗大户,需优先关注。

点击*Toggle Fragment Count*按钮,再点击下一帧

点击刚刚收集好Fragment Shader信息的第971帧,点击Fragment Shaders,然后按指令周期比例排序,可立刻知道哪些shader占消耗大头,比如图中的第877号shader,名字是“Shader 879”。


双击该877号shader,观察代码,可知是用于lightmap场景的shader

第877号Fragment Shader程序

所以,可输出结论一和初步解决方案。

结论一:场景是GPU性能消耗第一大户,需最优先关注。精简、优化场景mesh和贴图、精简lightmap是可行方法。

再点击下一个第619号Fragment Shader程序,

第619号Fragment Shader程序

通过经验可知,为渲染UI的Shader


UGUI的UI-Default.shader

所以,可输出结论二和初步解决方案。

结论二:UI是GPU性能消耗第二大户。留意到里面有discard语句,可能带来性能影响,所以应编写无clip版本的shader。并且精简UI、或进行UI纹理打包。

再点击下一个Shader,发现和UI Shader很相似,只是少了一个颜色的运算,所以也不用有mediump的color_2中间变量。可知是UGUI针对材质颜色为全白色时的优化版Shader

第622号Fragment Shader程序

所以,有结论三。

结论三:UI中,不需用颜色的,应保持此材质颜色为白色。

至此,当前帧的Fragment Shader权重较高者,皆已列出,剩下的Fragment Shader已变得性价比不高。
需转移目标,比如,Vertex Shader。
同理,切换至Vertex Shader,按cycle排序,找出性能消耗第一大户,第880号Vertex Shader。通过里面的代码出现“SH”,可知是球谐函数“Spherical Harmonics”,即用Light Probe进行渲染的主角Shader。

第880号Vertex Shader

所以,有结论四。

结论四:主角顶点数过多(图中为23469个顶点),是造成性能的瓶颈之一。

同时,留意到我们主角都是距离镜头很近的,所以,压根不需要雾的运算,所以,有结论五。

结论五:主角的Shader,甚至一些在不远处的敌兵shader,都需要去掉雾运算。

再观察下一个877号Vertex Shader,留意到是用Light Map进行渲染的场景,所以。


第877号Vertex Shader

同理,亦可以有结论六。

结论六:场景,如有可能,最好也去掉雾运算。

至此,第一帧分析基本完毕

第二帧:FPS状态,露出精细武器,无枪火特效

游戏战斗中是个多变的过程,不同时刻的两个帧显示的内容可能大相径庭。
所以需要更换另一种情况进行继续调优。比如FPS状态,露出精细武器,无枪火特效。

FPS状态,露出精细武器,无枪火特效

在之前的暂停状态下,取消点击收集Fragment数量按钮(Get the fragment count statistics),否则将会很卡,然后点击播放按钮(Resume Tracing),以和第一帧类似的方法进行数据收集。

取消Get the fragment count statistics,才继续进行操作

从收集数据看来,结果和第一帧数据并无质变。但由于知道变化的因素是精细武器本身,所以应特定确定该Shader的消耗。
此时,如果对武器Shader不熟悉,可以打开Unity,在Editor重现该情况,在Editor直接阅读Shader代码,如下:

精细武器的Shader:Bumped Specular

根据Shader特征ShininessGlossNormalmap等,回到MGD,也是按Cycle数从大到小逐个观察(因为渲染武器的消耗肯定不会很小),确定为第871号Fragment Shader。

第871号Fragment Shader,用于精细武器的Bumped Specular Fragment Shader

所以有结论七:

结论七:精细武器的Shader的Cycle比例(4.6%)和Shader指令,哪怕是用Surface Shader,也不算复杂,不是瓶颈。这可能是因为Unity的按平台编译Shader的优化结果。

第三帧:FPS状态,露出精细武器,开火,播放开火特效

FPS状态,露出精细武器,开火,播放开火特效

继续采集数据。并且点击开火,触发开火特效,然后立刻点击MGD暂停,并进行类似采集。发现有以下新的问题shader。

第862号Fragment Shader占用了10%的cycles

通过观察Shader代码,和枪火特效(还有额外的四周防护罩效果)的Shader一致,为

特效Shader,Particles/Additivie

留意到该Shader并不复杂,但却又雾的处理(理论上可以去掉一个Tint的颜色乘法),并且该特效在Unity观察overdraw也合理,所以也可以有结论八:

在Unity观察枪火特效overdraw也算合理

在Unity观察防护罩特效overdraw也算合理

结论八:枪火特效+满屏的防护罩特效会导致有额外10%的cycle产生。需去除雾的处理。因为需求原因,占用屏幕面积较大,但Overdraw程度尚算合理。

至此,关于Shader的调优在本文暂告一段落。接下来需要更多实地考察。
另外,操作上还有小技巧,可以通过Frames with features enabled的过滤,剔除没有详细数据的帧

可以通过*Frames with features enabled*的过滤,剔除没有详细数据的帧

内存情况

内存不会直接影响帧率,但也是性能的一方面表现。过高的内存可能是加载缓慢的诱因、可能会提高app后台后被系统kill掉的几率、也可能直接导致内存不足crash。
点击MGD里的Textures,并点击Size进行排序。

点击Textures,并点击Size进行排序

当前在killer出现了不合理情况有:

不该在战斗出现的纹理泄露到了战斗

结论九:主界面的图标从战斗外泄露到战斗内了。需要注意是否战斗内有错误的引用。可使用运行时检测工具打包Sprite Packer的tag是否战斗外、战斗内互斥。亦需要注意资源模块ResourcesManager是否还有资源引用,导致Resource.UnloadUnused()无法卸载主界面资源。

一个时刻只出现一个的icon图片可以不打包

结论十:军衔图标可能从战斗外泄露到战斗内了,也可能是战斗内就是需要用到。
结论十一:一个时刻很大几率只出现一个的icon图片可以不打包,放弃一定的DrawCall效率来换取内存,并且这样哪怕泄露也可减缓泄露的后果。

尚未提及的更多性能评估点

本文着重从最根本的Shader的Cycles数量进行分析,但尚未提及的更多性能评估点包括:

  • DrawCall是否合理,有否可能合并。Unity 3D游戏中,合并DrawCall会决定于LightMap,也会决定于UI层次间的atlas分布。
  • 是否有过多的OpenGL状态切换。

更多的优化细节,也可参考ARM® Mali™ GPU Version: 3.0 OpenGL ES Application Optimization Guide,或ARM® Guide to Unity Version 2.1 Enhancing Your Mobile Games

MGD(v2.1)尚待改进的地方

MGD(v2.1)尚待改进的地方有:

  • 在本次调优过程中,不能对已Capture的帧进行逐DrawCall重画(用户手册给出了原因);
  • 不能方便观察顶点模型;
  • 不能以柱形图直观地列出时间或Cycles消耗。

上述部分问题已在MGDv3.0得以解决。

About

DonaldW,客户端开发,现就职于腾讯魔方工作室群。
本文可随意分发、分享。但请注明署名。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容