作者:申江涛,腾讯互娱客户端工程师
商业转载请联系腾讯 WeTest 获得授权,非商业转载请注明出处。
原文链接:http://wetest.qq.com/lab/view/401.html

WeTest 导读

加入项目组的这段时间主要是承担性能优化这块的工作,同时也会去实现一些场景材质、特效材质以及工具。今天就性能优化这块分享一下个人的经验。


设备等级划分

设备等级划分是一切优化,LOD 策略的前提。

最新的 iPhoneX A11 GPU 性能直逼笔记本的集成显卡,要照顾三四线的小朋友,红米 1 你也得想办法支持。

画质选项高中低,游戏第一次启动通过设备硬件配置将设备匹配一个默认画质,匹配依据可以按照 CPU,GPU,内存等,也可以根据游戏类型做一些特殊处理,每一档选个代表机器,CPU,GPU 性能最好心理有数,可以参考下 CPU 的天梯 [1] 和 GPU 的天梯 [2],想拿详细数据的自己写测试案例跑。

默认画质匹配最好是基于配置文件的,这样即使上线后发现匹配规则有问题或者设备更新换代了想优化匹配规则也可以动过热更来刷新。

为满足美术大大们的追求,可以在高画质的基础上再划分一个超高配。

设备等级划分之后,就可以做一些 LOD 策略了,一定要做的就是划分各种特效的级别,其次场景最好也做一下,有条件的 UI 元素也做一下,对于非核心信息的 UI 可以在低配机隐藏。

关于 Shader LOD 的做法有在这个回答 [5] 里面提到,这里就不赘述了。

优化工具

磨刀不误砍柴工,熟练掌握 profile 工具绝对是打开优化之门的第一步。

Unity Profile

作为最简单也是最实用的 Profiler,即使是不做优化的同学也最好学会如何使用。它能够非常方便地分析出当前的 CPU 热点。

很多萌新会遇到无法手机连 Profiler 的问题,如果你也遇到了,请确定下面几个点(假设连 Android 手机)

1. 手机是开发者模式,且在 cmd 中输入 adb devices 能看到自己的设备

2. 配置了 Android SDK

3. 编译的是 develop build 版本

4. Unity 当前是 Android 工程

5. 如果不是在本机构建的,需要在 cmd 中输入 adb forward tcp:54999 localabstract:Unity-xxxx , xxxx 是游戏的包名。

新版本 Unity 集成了 FrameDebugger 和新的内存快照工具,更方便了。

在不开 Deep Profile 的情况下,看到的消耗比较粗略,很难定位具体的消耗,打开 DeepProfile 能看到比较深的函数堆栈,但是会有一些消耗,不过在可以接受的范围之内。

移动设备上没法开 Deep。

通常遇到的一个问题是手机上的 Profile 结果和 PC 上的结果不一致,解决方案如下

一切以移动设备为准,希望详细定位的话可以选择用 Profiler.Begin 打桩,或者在 PC 上开 Deep Profile 找到对应的位置,展开详细的堆栈来定位。

Adreno Profiler

蛮好用的一个 Android 平台的 GPU Profiler,之前很多人用来提取手游的资源,但是已经被高通抛弃了,已停止更新支持一些老的高通 GPU 的设备,这边确定好用的是红米 Note 1.

如果能找到可以用的设备可以,建议还是可以连一下看看,还是能看到很多东西的:DC 数量,绘制顺序,渲染 shader,动态修改 shader 看效果,贴图格式…

这个东西除了看性能还可以用来查一些平台相关的渲染错误。

XCode

首先你要有台 Mac 以及不算太老的 ios 设备。

首先要去 Apple 申请一个免费的开发者账号,然后从 Unity 构建一个 Xcode 工程,连上真机运行。

相对于 Adreno, Xcode 显得专业很多,功能更加强大,最重要的是,可以看渲染耗时!这对于分析 GPU 热点非常有帮助。

CPU 时间显示一直为 0,不知道试 Unity 的 bug 还是 XCode 的 Bug。

Instrument 可以看函数耗时。

备选

Mali Graphic Debugger:只能用于 Mali 的 GPU, 看上去很厉害,4.X 从来没有连接成功过, Unity5.X 的集成稍微友好一些,还没有深入研究。

Snapdragon Profiler:很卡,只能用于高端机,只能用于 Android 6.0 以上的系统,年底出了新版本,还可以。

Unity Frame Debugger:5.X 以上才有,很方便,没详细研究。

WeTest - UPA:和 Unity 官方合作的客户端性能测试工具,无需 ROOT 和接入 SDK,挺方便。

优化流程

如果想在后期轻松一些,美术的规范一定要定好,同时要有配套的资源检测,扫描工具。在定一些大的技术方案之前,各项消耗尽量做到心理有数,如果不确定就做一些实验,数据不会能骗人。

遇到上线前三天发现游戏只有十几帧的,这就只能砍效果了。

程序 ic 方面主要是对 C# 的语言底层机制的熟悉程度以及对数据结构的理解,一些明显有性能问题的写法要规避。

项目上线前两周左右就要开始对版本进行一些性能评估。高中低三档机的帧率,内存,耗电等都需要有数据。接下来就是

发现热点 -> 优化 ->继续发现热点->继续优化 –>继续…

这个过程肯定是没法由优化的人一个人搞定,最好是进行完一轮 Profile 之后,把需要优化的点记录下来,然后通过 tapd 等工具将优化任务派给对应的美术/程序同学,并去推进优化迭代,这其实牵涉到很多沟通工作。

关于 GC

GC 方面的优化很重要,原则就是任何大于 20B 的 GC 都值得被注意。GC 的优化比较琐碎,也比较考验基本功。

除了最简单的避免使用 foreach,避免频繁 new 内存,ToString。下面几个点可能是往往容易被忽略。

  1. GameObject.SetActive 会引起 GC

优化方法:对于渲染相关的,可以考虑是否隐藏 MeshRenderer 来替代,还有就是把 GameObject 拉到很远的地方,UI 也同样适用。

  1. C# 自带的排序有 GC

优化方法:自己实现排序算法,数量不多的直接写个简单的冒泡就行。

  1. 反射会引起 GC

优化方法:大部分的反射都可以用 dictionary 做缓存。

  1. List.Add 会有 GC

优化方法:List 底层是数组,在数组容量不够的时候就会扩充,会产生 GC。可以考虑在 new 的时候直接指定大小。

  1. Box Unbox 会有 gc

Boxing 的 GC 很隐藏,打桩也很难发现,Boxing 的触发条件:当需要将栈(Stack)上的值类型转换为堆(Heap)上的引用类型,这个过程被称为 “装箱”,它具有以下特性:

  1. 在堆(Heap)上分配空间

  2. 通知垃圾回收器有关新对象的信息

  3. 复制值类型对象中的数据并传递给新的引用类型对象

当初是发现了 Behavic 组件底层有 GC,跟到很下面的时候发现是一个 equal 函数

里面有一处改动是这样。

GPU 优化

不说 GPU 占有率,直接说 GPU 耗时 Xms 就是耍流氓。

通常 XCode 里面有 GPU 时间,对于一个 30fps 得游戏,理论上 GPU 有 33ms 的时间可以用,但是这个时间超过 20ms 的时候,就会发现再往上增加一些渲染消耗 (1,2ms 左右),GPU 耗时不会明显增加,而原有的一些渲染消耗可能要 1.5ms 的你会发现只要 1ms 就可以了,这个时候其实 GPU 负载已经有点过了,GPU 为了流畅度开始提升频率(iPhone 6 plus 亲测)

GPU 的优化其实就是和美术同学 Battle 的过程,找到那个平衡点,就算优化成功了。很多时候 GPU 的优化不仅仅是 Profile 看热点,而是需要你给出方案,这就很看经验了,萌新需要多问问老司机。

下面几个点一定要注意!

Overdraw! Overdraw! Overdraw! 注意每一块半透明是否需要渲染,面积是否能够减少。

Shader 的复杂度会影响 fillrate。

游戏场景内最好不要出现 alpha test,会影响 Hidden Surface Removal(HSR)的处理。

不要轻易尝试后处理,耗 CPU, 耗内存, 耗 GPU,中低配一定要关掉。

粒子系统请慎重使用,耗 CPU,多 Overdraw,数量和粒子总数都要控制好。

Static Batch 会消耗内存。

Dynamic Batch 耗 CPU,但是当需要渲染很多个同样的 MeshRenderer 的时候,对于减少 DC 非常有效,建议开启。

单局外的性能也要注意!

耗电优化

当优化完卡顿问题之后,本人就开始想着做一些炫酷的事情了,比如更酷的特效啊,后处理加起来啊,然后对于移动平台来说,你不是不卡就可以了,耗电,发热也是要重点考虑的事情。

耗电的几个大头,GPU,网络,CPU,GPRS,喇叭,屏幕亮度等等。上面介绍了几个 Profile CPU, GPU 的工具,但是电量怎么 Profile 呢?

关于耗电的优化踩过很多坑,参考网上能找过的方法挨个试了,比如用 ios 设备的记录耗电情况日志,或者是 XCode 的 Energy impact 等等,统统无效,其中的坑就不一一说了。只说一个绝对有效的方法。

使用 WeTest 云真机耗电量测试!基于自家的耗电盒子来检测电量,测得的结果精准。

还有就是设备一直处于充电状态,和实际使用有偏差,不过都在可接受范围内。

首先要测试出一个同品类游戏或者标杆产品的耗电水平,比如测得王者 5v5 单局得耗电如下:

接下来就可以测自己得 apk 了,测试得时候,最好可以通过作弊指令去动态开启关闭一些特性,得到各项的消耗,想要测得比较精确的结果就多次测取平均。

得到各项的消耗之后,就可以有针对性的优化了。

数据上报统计

数据上报统计是指将玩家的设备信息,设备画质选择,帧率信息进行上报,这样每次测试都能获取到很多有用的信息,利用这些信息可以进行相应的调整,比如说某些默认画质匹配占比,不同设备的性能表现,各类硬件的占比,比较卡顿的场景有哪些等等,同时也可以横向对比看优化的效果。

小结

记得刚加入团队,飞车刚好要进行第一次轻度测试,那次测试的收到很多的玩家抱怨各种卡顿,竞速赛卡,道具赛卡,连我们的策划同学在跑单人单局的也觉得卡…当时为了保证流畅把大部分的机器归为了低配机,还有很多玩家,设备是中高配的,为了开上高帧率,将画质设为低…..

到 PR2 的时候,经过一轮强力优化,也是和美术策划同学的通力合作,将默认中高配的设备从 20% 多提升到了 70% 以上,对于低配机,我们尽量会满足 30fps 流畅运行,对于中高配,60 帧的顺畅体验可以让他们觉得玩的是另一个游戏(Android 设备需要开始多线程渲染),如今正式上线,在 TapTap 这种黑腾讯游戏即政治正确的社区,好评也是绝大多数。

不过还是会有一些没有优化到的地方,比如

” Android 机开局的完美起步会卡啊!“

“-请期待年前的版本”

” 休闲区还是很卡啊!“

“-请期待年前的版本”

” 新手引导品质太低了吧!“

“-请期待年前的版本”

….

优化是件漫长的事情,因为总有可以优化的东西,这里的面是不是可以更省,那边 shader 精度减一下是不是可以…..自身也需要去掌握多种的 profile 技术,内功也要加强修炼才行,你拿着消耗去和美术大佬谈判,总得给个靠谱的解决方案吧。

对于一个老司机,应该在项目之初就能够把各个标准都定好,给出最好的解决方案,能做的不能做的都和大佬拍好,这样后面就舒服一些,但大部分还是一边现问题一边处理,然后慢慢地把规范和自动化测试流程搭建起来,这样也不失为亡羊补牢,这里面其实又涉及了一些 TA 工作。

特别感谢在优化过程中能够耐心给我解答问题的各位前辈,非常感谢!

篇幅原因,能覆盖的就这些了,没有涉及到的或者有误的迎大家指正。

参考

[1] 手机 CPU 性能天梯图

[2] Smartphone and Tablet Graphics Cards - Benchmark List and Comparison

[3] mobile cpu 上禁用 alpha test 的相关总结

[4] iOS Hardware Guide

[5] Unity 移动开发如何依据性能选择 shader? - 拳四郎的回答 - 知乎


腾讯 WeTest“耗电量测试” 已在云端部署,独家研制的耗电量盒子进行耗电量测试,精准定位手游耗电问题,点击http://wetest.qq.com/cloud/phone 即可体验。

如果使用当中有任何疑问,欢迎联系腾讯 WeTest 企业 QQ:2852350015


↙↙↙阅读原文可查看相关链接,并与作者交流