优化

《游戏性能优化之路》开篇

什么是性能优化

在软件开发的领域性能优化是永远存在的主题,不管你是做操作系统、做后端开发、做web前端、数据库开发、开发编程语言,甚至开发指令集本身,你永远都会遇到。只不过我正好身处游戏行业,我也只能分享游戏相关的性能优化。

那什么是游戏性能优化,我的理解是:让游戏在目标设备或者尽可能高覆盖率的设备中让玩家不受到设备硬件限制地流畅无阻塞体验到游戏开发组预期玩家能够体验到游戏内容的工作。

这里有几个关键点:

  • 目标设备:什么设备是目标设备
  • 流畅无阻塞:什么样的帧率符合预期,需要满足多大的内存以防止设备闪退
  • 预期玩家能够体验的内容:一个游戏如果无法让玩家体验到实际希望玩家玩到的东西,那优化再好也没有用

性能优化的特点

游戏性能优化是一个很大的切口,在当今游戏开发当中性能开发依旧是一个巨大的挑战。但是性能优化和其他的模块开发有显著的不同,性能优化并不针对某个模块本身负责,也不存在其他开发任务一旦做完之后事情就告一段落,可以说,只要提交没有停止,性能优化就永远没有结束。性能优化如此特殊,所以也导致做优化的人也是千人千面,同样是做性能优化的开发者,技能树、工作内容完全不同。我在下面会简单介绍一些性能优化工作的特点。

性能优化是主观的

与此同时性能优化也是一个非常主观的东西,一个游戏到底做到什么样的程度才算是拥有优秀的优化,每家厂商的策略不一样:

对于小游戏来说平时可能根本不会关心性能优化,先把游戏本身做出来,到时候通过常用的工具profile一下发现热点并且解决就可以了。

而对于一些大型的主机厂商或者是重度的手游厂商来说性能优化决定了一个游戏的成败。

对于主机游戏厂商来说能不能在主流主机上流畅跑起来决定了游戏本身能不能如期发售,以及在主流主机上能塞下多少的内容也决定了游戏的销量。

而对手机游戏厂商来说优化到什么程度决定了能够覆盖多少的用户群,如果一个游戏面向的更下沉的用户那么需要关注游戏使用了多少内存、包体是多大、在什么设备上能够做到最基本的游玩体验。

相反,如果一个游戏一开始就希望做到业界效果的前沿,在开发的时候可能会拉满效果,目前最新的手机甚至都无法跑满帧,所谓“战未来”,怎么把最先进的渲染技术或者超大的内容量塞入手机当中就成为了性能优化人员需要面对的挑战。

当然这一切不全是性能优化人员能做的,更多的涉及到和不同专业同学的配合才能在尽可能多的机型上把性能和效果达到最佳的平衡。

而且一个游戏是否需要花大量精力优化,优化到什么程度也取决于项目制作人对项目目标群体的预期,以及整个项目技术水平的评估。所谓有牛人团队有牛人团队的做法,普通团队有普通团队的做法。但是似乎现在的很多项目负责人(特别是大型项目组)总有一种错觉,认为自己可以同时吃下高端机型用户和超低端机型用户。笔者认为,高端机型优化和性能下探完全是两个不同的技术方向,往往最后导致效果做不过专注效果的竞品,下探打不过性能特化的竞品。目标明确,集中力力量做大事,能做到效果和下探的其中一个就已经不易,同时要达成这两件事情难于登天。

性能优化是多样的

几乎所有模块都会涉及到优化,Gameplay、渲染、物理、语言底层、操作系统,etc..

我相信应该没有人可以同时精通所有这些领域的知识(至少在我认识的人当中没有)

所以对于性能优化人员而言,或许并不能同时精通所有的游戏开发细节,但是他一定需要知道游戏的所有开销来自哪些地方,这样才能在不同的模块之间进行平衡,把游戏的性能尽可能放在游戏本身最关注的地方。

戴森球计划或者纪元系列游戏,CPU开销是个不可小觑的开销,如何将大量的计算开销进行优化是一个难题。现在一个普遍的方案是使用ECS、充分利用硬件的局部性原理榨干所有硬件的性能。

而对于神秘海域、黑神话等游戏来说,同时在运行的CPU逻辑或许并没有这么多,大量的开销用于渲染来打造更好的电影级画面,那么如何将更新的渲染技术融入到游戏当中并且通过各种方式优化现有的渲染开销则是这些项目最需要关心的主题。得益于UE5开源的Nanite技术,很多之前没有足够引擎技术实力的公司也可以将重心放到创作上而更少关心实际的引擎渲染技术细节上。

对于主机来说需要充分利用主机本身的特性,或者根据主机的劣势来进行优化。很多主机游戏在资源上会复制多份来优化加载排布减少机械硬盘上的加载时间。而手机上则需要尽可能减少带宽降低功耗,避免出现降频的情况,PC上则没有这种情况,渲染上可能会根据TBR和DR来区分渲染管线。

在语言层面,如果一个游戏是基于Unity开发的,则可能需要知道垃圾回收的实现、C#如何转换到il2cpp,关注生成的汇编代码的质量,减少memorybound或者分支跳转整体提升性能。即使是用C++进行开发主语言的UE,也会通过大量的模板操作来将运行时开销转移到编译时,或者是使用lto、或者PGO等成熟编译优化手段来提高游戏性能。

我提到的所有的这些仅仅是凤毛麟角,在实际大型项目中需要处理的性能优化问题绝不是一个性能优化同学就能完全搞定的,需要精通各种知识的开发者通力合作才能榨干最后的硬件性能。

性能优化是一个系统性工程

很多刚接触性能优化的开发人员往往认为性能优化是一个技术问题。在我看来,这个观点只在某些情况下是成立的。

例如现在你是一个性能优化的负责人,你可能需要关注这些问题:

  • 我们需要满足什么样的性能?
  • 我们怎么知道目前有没有满足目标的性能?
  • 我们怎么达到当前目标的性能?
  • 我们如何防止性能退化到目标以下?

其中和技术最相关的只有第三点。其他全部都是项目中需要通过沟通和搭建管线需要解决的问题。我在后面会描述我在解决性能问题时候的流程。

我以前参与过的项目往往会顾及不全所有的这些点,或者在某一些点上面出现纰漏。在一个大型项目当中,这里的每一个点可能都需要至少大于一个人去关注,这些人不一定是性能优化人员,但是一定是性能优化者引导,并且教会他们如何去做的,性能优化者很多时候承担一个牵线者的角色而不是实际开发者,这也导致了很多其他岗位的角色认为做性能优化的人:摸鱼、好像每个模块都不是很了解,但是需要指导别人去做事。从而产生一种反感的情绪。为了在给其他人提出需求的时候不会让其他人对你的专业能力或者做法产生怀疑,最好的方式就是摆数据和事实,以及展示该事项的收益和影响。在做性能优化的生涯当中我逐渐意识到这是一个性能优化者必须具备的能力,否则和其他项目成员产生冲突可能会是迟早的事情。

最基本的性能优化流程

不管是什么游戏,性能优化的流程往往分以下几步

  1. 设立目标:游戏要跑在什么设备上,需要达到什么帧率,占用多少内存
  2. 测试&发现性能问题:游戏目前的性能情况是怎么样的,每帧的耗时、占用的内存以及所有优化者关心的指标,是否满足第一步中设立的目标?
  3. 定位问题:游戏中不满足目标的指标导致的原因是什么,是Gameplay?是资源?是兼容性问题?
  4. 修复问题:这是绝大部分性能优化者会做的事情,优化代码,设计或者是资源
  5. 回归问题:在修复之后性能变化是否符合预期,如果不符合预期则回到第四步
  6. 问题修复完成,回到第二步

性能优化者的工作永远围绕着上面的这些步骤进行,如果你发现自己做的事情不在这些事情的范围内,那可能你需要重新思考你所做工作的意义了。

这已经是性能优化最缩略版本的步骤了,我无法想象其中的任何一步缺失会怎么样。

设立目标

什么样的才是目标

说实话,这里的目标和传统意义上项目管理的目标大致上没有什么区别,只不过我们能够通过拆分目标来整理出每一个模块的目标。

最低配置机型是什么、推荐机型是什么、在对应设备上使用的内存是多少、功耗是多少,最终设备上需要达到的展现效果是什么,这些都是目标。除了总的大目标以外,游戏的DC、DP、模型的面数、程序的耗时都可以拆分成小的目标,但是要知道所有的这些目标都是以功耗、内存这些大目标存在的,一旦没有大目标,那么这些小目标将失去它的意义。

我们需要有个目标

设立目标是性能优化的第一步,也必须是第一步。如果做性能优化的时候不知道性能目标,那么性能优化永远做不完,设立目标相当于为我们定义了一把尺子,通过这把尺子我们能够知道自己的工作完全情况如何,它告诉我们我们的工作是否是有意义的。

没有尺子可能会导致下面的几个问题:

  • 性能优化可能会投入无效工作,例如一个游戏仅面向PC平台,内存占用大概是5个G左右,那么我们需不需要投入人力去优化几百M的内存?如果我们的目标是8G的设备,那么我们完全不需要花时间,但如果我们需要面向4G甚至更差的机器,那么我们就需要花人力达成目标。
  • 我们同时需要满足流畅体验和保证内存占用少,那么如果我已经满足的内存目标,我就可以把更多的精力投入到逻辑或者渲染耗时上,如果没有目标,我们如何知道什么时候应该做什么事情呢?
  • 如果不知道目标是什么,对于功能开发同学而言做法也会变得不同。

我们应该有一个什么样的目标

不管你的项目做游戏是为了让玩家感到快乐,还是为了赚米,你都应该有个明确的目标。

我这里就以某商业公司定目标为例,众所周知,商业公司一切都是为了赚米,而不是为了个人的技术成就而上一堆酷炫吊炸天的技术。即使是做技术研究,那么至少也需要看一下市面上有没有设备可以运行你的成果。同样的和第一点一样,如果不能明确自己的目标用户,那么你定出来的目标设备是毫无意义的。

例如:我作为项目的Owner,我需要知道项目的营收应该是多少,根据营收目标我们可能需要多少的玩家为我们进行付费,我们的DAU大概是多少,可能会覆盖到怎么样的玩家群体?我们的目标用户是下探还是面向高端玩家?这部分的工作恐怕需要市场部的运营同学才能给出答案。

但是只有基于目标玩家,我们能够定出目标机型,是面向近几年的手机,还是需要支持7、8年前的老古董(没错 说的就是iphoneX)?

基于目标机型,性能优化同学能够给出大概能够接受的游戏功耗和内存占用,例如iphoneX仅可以使用1500M的内存,如果再往上的话便有闪退的风险。

这里游戏的功耗和内存便成为了性能优化(可能是某一个版本)的最终大目标。当然,在实际项目中,我们除了最低支持机型以外还需要给出中端机、高端机是什么机型,以及不同档位的机型需要满足玩家怎么样的体验。在这里制作人、策划、运营需要有个明确的共识:例如对于低端机我们只提供最低限度的游玩体验,而中端机需要有一定效果上的支持,高端机需要能够达到市面上有竞争力的画质水平。

定出了高中低端机型之后,我们可以开始进行我们接下去的工作了。但是定目标的内容并没有完全结束,美术资产、游戏内容如何分级需要在游戏开发的进行过程当中穿插决定最终的资产规范、内容性能分级,例如NPC的数量、建筑物的密度。最终形成一套在工作流体系中同学都能有所共识的规范。

也就是所谓的管线。

测试&发现性能问题

回归软件的本质

我有面试过无数应聘性能优化岗位的求职者,但是我总是很意外他们会迷信Unity或者UE提供的原生profile工具。他们没有深究过Profile中提供的数据意味着什么,这些数据是怎么来的,他们似乎并不是很关心,他们只关心这些数据是否确实下降了,他们甚至不知道自己的budget是基于什么来的。

要profile CPU耗时或者内存,首先需要知道CPU的耗时从何而来,以及内存在设备中是如何分布的。这在不同的操作系统中处理方式都是不一样的,不同操作系统中本身的内存操作本身就不是统一的,除了最基本的虚拟内存的概念,每个操作系统中都有各自衡量自己内存占用的方式,例如ios中有footprint,android中有PSS、RSS、VSS等。对于CPU则存在空间时间局部性、分支预测等问题来影响程序的执行效率。一个经典的问题,同样一个二维数组for循环方式不同耗时却会截然不同。

如果你不知道这些基本的操作系统知识,那性能分析将会是一场噩梦,你可能会完全不知道发生了什么。你也不知道你手头的数据到底是怎么到你的手上的。你对抗的是未知。

了解你的工具

很多初级的性能优化人员会有这样的问题:为什么Unity提供的Snapshot中的内存和iOS上的Instrument中录制出来的内存不能百分之百匹配起来。

这个问题的原因是Snapshot和Instrument本身也是软件的一部分,他们只是将自己能够观测到的数据反馈到profile人员,而他们观测不到的数据,他们无法提供,他们也不会说明自己是通过什么方式拿到这个数据的,唯一的方法是尝试去看它们的源码。据我所知,没有任何一个性能测量工具可以覆盖所有的性能指标,了解你的性能指标来源非常重要,关注操作系统的官方文档,和一切有关的讲座,越接近底层你可能拿到的数据就越准确。

当然一个更好的方法是开发你自己的profile工具,当然这需要比较多的经验,包括你需要怎么拿到操作系统的数据(有的时候你甚至需要逆向操作系统的接口),以及如何尽量减少你的工具的overhead。自己开发的好处是你可以掌握一切的细节,并且把数据按照你感兴趣的方式组织起来,因为操作系统提供的数据是业务无关的,而你可以把这些消耗和你的业务关联起来,这意味着你可以定义更贴近业务的目标,定位问题的难度和目标可行性度会大大增加。

关注不同的发布版本

很多刚刚接触性能优化的人员会犯以下错误:直接在编辑器下或者是用debug包采集profile数据。发现了一些自认为的瓶颈,但是最后发现这个问题在发布包中并不存在。

对于性能优化来说,最重要的是两个包

  • 用于Profile的Profile包(在UE中叫做Test包)
  • 最终会放给玩家的Release包(UE中叫Shipping包)

其中Profile包中包含了一切Profile相关的基建,内存统计、CPU采集等但是剔除了所有辅助开发用的基建,一般会包在Debug宏当中,相当于测试当中的白盒测试,性能开发人员可以在其中增加打点,但是尽可能让Profile包的性能接近于Release包。

而Release包中排除了一切非发布相关的内容,只能通过操作系统接口来拿到最基本的性能信息:FPS、内存、CPU占用率等。但是一些操作系统上想要拿到这些参数并不容易,github上会有不少的库用于采集这些数据,也有类似于perfdog的专业工具用于采集信息(可惜并不免费)。

实际上在项目开发的过程当中会需要一个叫做PreRelease的包体,因为在商业游戏项目中,往往在release包中会添加反逆向的基建,某些profile手段会失效,还有一些情况是发现仅存在于release包中的问题需要对应的调试手段。

持续测试和监控

性能优化并非是在做完某一件事情就结束的工作,上面也提到了,只要提交还在继续,性能优化的工作便不会结束。

所以如何持续测试并且发现问题是性能优化工作中相当关键的一点,倘若你没有监控性能的能力,那么再厉害的优化技巧也无勇武之地。

监控和测试和项目性质和游戏内的功能息息相关,吃鸡游戏和当今的重度二次元游戏的测试监控手段截然不同。但是不变的是自动化和监控频率的极致追求。

我们明确一下测试和监控的目标:

  • 可测量的,在前面关于工具的讨论当中
  • 可以复现的,只有充足的自动化才能做到持续复现
  • 尽可能覆盖业务和流程:了解你的业务,了解发布流程,不要有漏网之鱼
  • 尽可能的高频:两次测试时间的间隔越久,追溯问题的成本就越大

如果你能达成以上的这些点,对于性能测试而言,仅仅差异的就是什么样的case,以目的出发设计case,定义所需采集的数据。

定位问题

测试和定位

很多时候我们会混淆测试和定位问题本身,测试是性能劣化之后导致的结果,而定位则是我们需要找到的原因。很多测试case本身会暴露问题的所在,但是这并不是最终的原因。例如:我发现地图当中的粒子总数变多了,但是我并不清楚是场景相关的粒子过多,还是角色释放技能之后产生的粒子过多。有的人可能会说那把场景粒子和技能释放的粒子case分开就可以了。但其实即使知道是场景粒子还是技能粒子本身也是不够的。场景粒子多是因为布设的问题吗?还是streaming系统出现的bug?还是说本身需求如此需要改变做法。

所以定位问题是一个复杂的过程,性能优化者就像一名侦探一样顺藤摸瓜,即使是feature的owner,很多情况下也不能知道具体问题的所在,每一个环节的人只能知道自己那一块的知识,面对整条链路的问题,即使是身在其中的制作者可能也难以窥见全貌,这个时候TA、TD的作用很大程度上会体现出来。但是这里我们先按下不表。

这是个bug,还是一个未做的性能基建?

在发现问题之后,我们需要问自己这个问题。当然很多时候,你不是feautre的owner,所以你也不能回答出这个问题的准确答案。最好的方式是去问问对应的feature owner,找到写这个代码的老哥,这样的表现真的符合预期吗,这是策划要求的feature,还是说我们的游戏出现了bug。

如果说游戏出现了bug,那么很好,这件事情交给对应的程序老哥就好,我们只需要在对应的地方加上新的检测点,以备下次遇到这个问题快速定位到问题即可。

但是如果我们发现者确实是个feature,那么我们便要思考我们是否需要改变做法,或者说是否存在一个性能基建能够将这个feature化腐朽为神奇。

但现实的很多情况是,我们发现出现性能异常,下意识地直接开始着手进行优化,很多时候这都是无用功,反而浪费了时间。

业务相关的性能问题

如果说性能是开源和节流的话,那么玩法优化绝对是后者。

对于大部分的性能优化者来说,业务相关的性能优化可能吃掉了接近90%的时间,而profile是一件如此枯燥的工作,如果你的所有时间都投入在profile,很有可能工作流上出现了问题。

自动化测试是减少定位问题时间的最主要手段,比如完整定位到问题需要100分的努力,那么我们的自动化测试,不管是分case还是根据业务拆分数据帮我们定位到80分的样子,就已经可以帮助我们节省大部分的时间了,我们需要做的是尽可能花更多的时间在如何修复这个问题上面。

更重要的是:吃一堑长一智。

玩法性能往往不需要非常高超的专业知识,但是需要对项目内各个业务的owner十分了解,甚至超过了自身所需要的知识水平。你或许不了解3C相关的知识,但是没关系!你知道是谁负责这件事情的,并且知道这个业务的某些代码或者某些资源导致了内存、cpu或者是gpu的瓶颈,那么你就已经可以承担这一个岗位了,至于如何修复你可以和feature owner一起出主意,但是大部分情况下你出的可能都是坏主意(如果你真的做过这个岗位,你可能深有体会),因为业务同学可以从业务角度直接改变做法从根本上解决这个问题,而你,作为一个不了解业务的性能优化者(如果你精于业务那么当我没说),只能从更底层的角度来解决问题,你可能可以优化50%,但业务开发者可能直接把这件事情直接干掉。

虽然玩法优化本身看上去平平无奇,但是确实每一个项目必须拥有的中流砥柱。

业务无关的性能问题

通用优化,一般来说是开源的那部分,做这部分优化的同学在别人看来往往是有着不俗的才华,做着让人十分羡慕且具有成就感的工作(当然实际上并不是这样)。例如做unity项目时有一些项目会主动魔改il2cpp以获得更高效的性能,或者是在项目测制作性能优化相关的基建。当然,做这部分工作的同学确实会有更高的要求,因为一旦涉及通用优化就意味着你需要提供比传统商业引擎或者引擎开发更优秀的方案,这意味着你对某一些模块有着较高的掌握程度,当然现学也没问题,但是前提是项目有这样的空闲人力来支持你这么做,否则所有项目都会以玩法优化为优先,因为玩法优化的性价比往往比通用优化的性价比来得更高。通用优化中有较高性价比的,一般不是被引擎提前做了,就是项目制作过程当中已经处理过了,本质是作为一个feature去做的而不需要你来发现。

当然了并不是说不需要通用优化,通用优化是作为一个项目或者开发团队的护城河存在的,如果一个项目组掌握了市面上其他游戏厂商不曾掌握的优化技术,那么也就意味着你有更多的资源提供给游戏制作使用,你在il2cpp里面优化出来100M内存,那么你就比友商能多用100M的内存,你获得品质竞争获胜的概率就越大,这也是为什么国内厂商团队内部性能优化团队越来越壮大的原因。当然,在上一条中也说了,如果要脱离一直进行玩法优化的循环,自动化必不可少,尽量少犯重复的错误,让你每次的优化成为项目的一部分,引用国内某知名up主的slogen,“无限进步!”。

修复问题

技术是关键问题吗

我在大学刚毕业的时候我总是会陷入一个误区,我总是认为,游戏开发问题大部分都能通过技术解决,如果有充足资源的情况下,一个团队的技术上限决定了游戏制作中能解决多少问题。

性能优化也是一样,刚接触性能优化的我认为,充足的资源的条件下,只要知道对应的解决方案,那么这个性能问题便一定可以解决。

这里其实忽略了一个非常重要的信息,游戏制作是一个系统性工程,除了技术还有人还有其他岗位的角色,代码开发本身不能脱离这一整套工程中的其他部分。这里举几种可能发生的情况。

第一个例子:游戏当中发现某个做法有问题,底层框架甚至都存在错误,这个时候有一位能力很强的开发者加入了团队,他知道业界最新的解决方案,他也发现了这个问题,大胆地提出了要替换框架的解决方案,这个方案从技术角度来看无懈可击,从理论上可以无感替换当前的底层框架。

但是项目的主程序给出了否决票,因为从理论上确实没有问题的情况下并不能完全推定有没有其他问题,因为主程可能并不精通这方面的知识,所以不可掌控的不安全感完全超过了他希望解决这个问题的需要。

另一个可能的原因是,发现新的方案需要改动所有相关的美术资产。美术老大说,当前项目的人力不足以替换所有的美术资源,如果给不出足够充分的理由不会推进这件事情。

所以这位技术大牛,开始觉得为什么所有人都和自己对着干,这明明是一个理论上没有风险并且收益很大的修改。

第二个例子:某个做小游戏的公司,团队当中的成员都不是什么大牛,大家都是十足的实用主义者。虽然没有什么高超的技术,直接使用的UE5默认提供的Nanite渲染,在逻辑开发中也使用蓝图,发现热点的时候把蓝图中性能热点相关的部分换成了C++实现,就这样鼓捣着把项目做上线了。虽然性能和渲染效果不如很多3A大作,但是好在他们也并不打算支持太低显卡的设备,因为确实能力所限,最终依靠玩法本身吸引了一批属于自己的受众。

第三个例子:某个做过多款成功游戏的大公司,团队当中各个都是之前爆款项目的组长或者是大头兵,这一次老板信心满满要做业界领先的大作,团队中的每个人也希望游戏中的模块用上业界顶尖水平的技术,每个人都希望能够用上自己发明的最牛的方案,老板提出的每一个问题都有完美的技术解决方案。前期大家做得都非常开心,但是随着时间推移,模块越做越复杂,但是游戏核心内容却迟迟没有结论,性能优化同学在复杂的模块和概念之间疲于奔命,美术总是以目前demo期为理由往游戏里面加入完全不符合性能要求的资产,最后这款充满所有人信心的大作胎死腹中。

其实这几个例子在现实当中或多或少都有原型。我想让大家了解的一点是:技术本身没有错,但是游戏开发中技术并不是全部,就像打篮球时你并不能靠你自己战胜对面的所有人。

推进是关键

当然我必须事先说明的是,作为技术人员,我们的本职工作是让游戏能够用上更好的优化手段。而我这里要说的推进则是如何让其他人接受我们,如何让本身不了解技术全貌的leader接受你的技术方案,如何说服美术和策划采用更好的制作方案,当然,最最重要的是,我们如何知道自己想做的事情是对的。

当你在准备解决方案的时候必须先想两件事情:

  • 我的解决方案能带来怎么样的收益?这个收益是否符合性能目标?还是对应的性能目标已经达成了
  • 我的解决方案会带来怎么样的影响?对于游戏稳定性是否会有影响?是否会影响项目当中其他人的工作?是否会增加其他岗位同学的工作量和心智负担?

首先要先想清楚这两件事情,对应的收益是否能覆盖所带来的影响,最后是赚了还是亏了。

想清楚之后再拉所有关键节点上的人来确定这件事情,而不要做一个孤胆英雄。

不过对于通用优化来说,与其说是优化者,角色更像是开发者,所以沟通问题会相对小非常多,只要能明确收益和影响就足够能说服负责人,也就能做好这份工作。

对于其他模块开发同学来说,每一个feature都市一个封闭的团队,在这个团队中尽可能同步好信息就可以了,但是对于性能优化而言,每天你接触的都是不一样的团队,这些feature团队当中有哪些人,具体负责什么事情你必须要清楚。

拉到了所有人之后,首先要和大家同步你的结论,收益和影响。对于某些团队的人来说可能有其他的考虑,那么你就需要调整你的方案。

当方案确定下来之后,你需要找到推进者,这个角色可能是你,也可以是TA或者TD或者其他程序。但有一个很重要的点,这个人身上带有性能的激励。如果你找到的推进者身上看不到任何你在推进事情的激励,那么很大概率你的事情会被遗忘。这个激励可以是对方leader在年度目标当中指定的性能目标,也可以是你告知的如果未推进成功之后产生的严重后果,一旦有了激励,你的推进人自己就会将事情推进下去,并且做得比你更好,因为他是更贴近相关业务的那个人,他知道该怎么做。

所以,实际上性能优化很大一部分的工作更像PM,他除了需要定位问题,制定解决方案,还需要为每一个管线上的关键节点牵线搭桥,最终将最理想的做法落地。一个优化技术再怎么巧妙,无法落地就没有任何意义。

积累你的工具箱

性能优化就像一个塔防游戏,在正式铺量开始之前,性能优化的工作其实相对而言是比较清闲的,因为真正的问题还未暴露出来,但是这个时候恰恰应该去积累各类的性能优化基建。因为当性能问题大量袭来的时候或许你已经为了性能问题忙于奔命而没有时间提高性能优化的效率了。

正确的性能优化基建开发顺序是这样:

  • 项目早期:着重框架层面的基建和框架设计层面的优化
  • 项目铺量:针对各个玩法模块的优化,尽可能找到最佳的实现方案
  • 上线:着重微观层面的优化,对上层无感,上层优化大部分可以通过已有基建解决大部分情况无需性能优化者参与开发

其中我在项目当中学习到的一个经验:

在项目开发期一定要留好后路,scalable的框架要优先准备好,例如Streaming的Scalable、LOD的Scalable、渲染效果的Scable,在后续设备分级的时候一定会用到,当开发期来不及优化的时候也能够作为最后的手段存在。

在项目开发期玩法都还没定下来的时候一切的性能评估都是拍脑袋,在真正目标机型跑起来之前没有任何优化技术能保证目标设备能够一定承载你的游戏。当前版本的优化基建已经无法满足目标的时候可能就需要祭出scalable基建做最终的后路。当然,如果用不到最后的底牌自然是好事。

回归问题

尽可能提高可环比性

当我们修复完问题之后,我们怎么知道自己做的是否有效果呢。这个问题看似简单,但是在实际操作当中有非常多的细节。

首先是开发环境,我们是否能让QA产出一个和先前有问题的环境仅带相关修改的包。例如使用perforce可以使用shelve出包,git可以单独拉验证的分支,相比之下svn会弱很多,所以现在大部分的团队放弃svn也有其中的一部分原因。

其次是测试过程必须需要保持一致,这一步自动化case是不可缺少的,但是仅仅有自动化case是不够的,游戏当中有太多的随机因素,例如随机在大世界散步的npc、对局当中的随机种子等等,为了完全复现先前的自动测试过程不同的项目会遇到不同的困难,其中辛酸只有对应的case开发和性能优化同学能够体会到。

除此之外有一些测试还会受到外部环境的影响,例如手机是否要带散热器,手机降频会严重影响到手机的实际表现,另外环境问题本身也会影响手机功耗墙的表现。特别是测试功耗的时候,环境的湿度、温度、芯片的体质都会影响测试的结果。专业的测试人员会关注到这一点,虽然性能开发人员算不得专业的测试者,但是这些细节也同样值得注意,一份错误的报告可能会浪费你一下午的时间,甚至影响最后的决策。

吃一堑长一智

这句话对于所有人来说都有意义,但是对于性能优化来说尤为重要。因为性能优化不像其他的模块开发,模块开发完之后可以持续迭代,但是性能问题出过一次之后,即使修复完了后续还是可能会出现。所以规范与检查的积累和流程的积累尤为重要,越是老的项目其流程和规范越是包浆,以至于没有自动化的话没有人能掌握到底有多少的检查,但是出问题的概率也大大降低。

修复性能问题之后,往往有几个事情还是需要持续做的,一个是将相关关键数据记录到当前监控中,其次是考虑是否需要为相关case添加自动化测试,既然有性能问题出现,那必然是部分模块的自动化测试监控没有覆盖到。我个人还是更推荐进行自动化离线后验,自动化运行测试case存在运行时间的问题,测试的内容越多,其测试频率也就越低,提高测试频率的成本也就越高。

当然修复完问题也是积累性能工具箱的好时候,看看这次的优化是否存在一些潜在的通用基建用于其他模块,积累越多,后续花在定位问题的时间就越短,用于投入通用优化的人力也就越充裕,项目潜在的竞争力也就越强。

总结

这一章基本介绍了一下我对性能优化整体流程的理解,其中没有包含任何的性能优化实例,但是在做性能优化之前,最重要的一点是明白自己在做什么。

如果你不清楚自己的性能优化是为了什么,那么大概率是在自嗨,今天看看profiler里面有没有什么时间长的,挑几个改改,和闲来无事挖个耳屎没什么区别,对项目的意义也没这么大。

真正有意义的优化在于

  • 知道项目需要什么,目标是什么
  • 迭代基建和监控流程,加速问题的定位速度,从节流角度尽可能减少业务性能问题的出现
  • 在解决业务性能问题的前提下将人力投入到通用性能优化,为项目争取更大的竞争空间

而要推进优化,则要清楚了解优化的收益和影响,不要忽略‘人’的因素,一个不符合项目现状的优化手段即使有再好的效果未必就是一个好的优化。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注