优化

《游戏性能优化之路》番外:开发期性能目标悖论

上一篇文章写了如何制定目标,但是实际在制定目标的过程当中,我们需要的往往不只是取什么数据数据源是什么,而问题是什么样的目标适合我们的项目。

这里有一个显著的悖论:我们还什么都没有,怎么定性能目标和规范?如果没有性能目标和规范,那我们应该如何指导我们的开发和资源生产?

尽早确立目标真的是合理的吗,如果不是,那么什么时候开始制定目标,怎么样确定目标。

性能优化的过程不像开发需求,先做第一步,后做第二步,而往往是穿插进行的,目标确定的时间不但会很晚,而且在项目的开发过程中还不断会变化,不同项目阶段的性能目标也会有显著不同。

项目原型阶段

确定项目的定位,确定最初的机型目标。

在项目的开发过程当中有大量的feature还没有完善,大量的临时美术资产。倘若这个时候和美术说:“你这个资产可超标了啊”,那想必你会被喷得够惨,在feature和美术资产还没落地的情况,甚至是玩法都还不确定的情况就开始盲目跟进性能是不明智的。

这个时候恰恰是我们韬光养晦的好时机。开始搭建你的性能平台、动手开发你的性能采集工具、以及尽可能补齐所需要的性能采集接口等等。这将成为后面推进性能效率的重要基础,可以说这个阶段你的准备越完善后面你要加的班就会越少,能解决的问题就越多。

不过这个阶段有一个需要确定的是,项目的目标受众和定位是怎么样的,我们是战未来,还是探下沉市场,这很大程度决定了技术选型,也很大程度影响到后面性能优化得方向。

当然,我们需要有一个对目标设备和性能参数的最初步设想。

在这个阶段,只要游戏不挂能跑起来,就不要管太多运行时性能的问题,磨刀不误砍柴工。

让项目的第一个样本跑起来

了解你目标的组成部分,开始组织目标地图,但蛋糕怎么分待定。

这里的第一个case取决于项目的玩法,例如崩铁主要玩法分局外跑剧情,局内回合制以及各种活动玩法。而第一个case,可以理解成第一个能够进去玩的场景,一个能跑通的回合制战斗。

这个时候我们是时候该测试一些性能了,但各种Feature依旧在开发,美术依旧存在大量的白盒资产,我们依旧无法根据现状来确定我们实际的目标,因为类似LOD、HLOD等feature不存在的情况下,我们测出来的数据和最终面向玩家成品下的数据依旧有巨大鸿沟,这个时候你如果想要降低内存或者功耗几乎是没有什么手段也没有什么意义的。这个阶段应当开始验证性能自动化测试平台的可用性,验证部分性能case稳定性,并且排除一些case当中变量,帮助我们在下个阶段尽可能少被一些蠢问题绊住手脚。

但是有个样本是很重要的,就像一些做餐饮业的公司一样,往往会开启第一家示范店,用于验证商业模式,并且发现各种各样的问题,做性能也是一样。需要一个实验田,对于渲染相关性能,往往会采用devlook场景的方式来验证效果和性能,而对于客户端逻辑而言则是一个最基本的case,能够完成最简单的游戏流程,如果游戏流程不太好自动化,定期手动跑测同样也是很必要的,如果流程频繁变化,维护case的成本往往会超过自动化带来的好处。

这个阶段,我们开始对游戏主流程框架开始有明确的认知,逻辑调度框架基本定型,一些子目标的框架也逐步开始建立,打点项逐步扩充,性能监控开始出现雏形,游戏的性能热点逐步开始明确,同时反向推出有哪些性能基建需要逐步开发,性能feature和性能测试成为一个自循环,我们要扩充大世界,那就开始扩充Streaming,我们要增加NPC,那么我们便开始实现GPU动画,我们要大规模逻辑,那么我们开始ECS。切忌不能下意识认为,我们可能会需要这个而去开发一个需要巨大工作量的性能feature,可能会浪费很多时间,最终却带来不了多大的收益。

因为有大量的性能feature提出,一些原来可能成为瓶颈的问题,后面可能不再成为问题,但因为不断填充需求,新的问题也不断涌现。

这个阶段实际上,我们还是很难确定最终的目标。但是我们已经不再毫无方向,而是了解游戏的耗时、内存、功耗分布了。我们不需要非常明确,但是可以开始进行分模块了。例如场景内存、角色内存,或者是逻辑耗时和渲染耗时。我们可能依然无法达到目标,但是我们知道为了达成分蛋糕的目标我们需要做什么,如果做不到还有什么替代手段,例如:低端机的shadow用更省的方式,关闭部分pas,或者是HLOD距离和LOD的Scable。其中,我们要尽可能早得实现各种主流的Scalable手段:支持完备分档、控制各个维度LOD、渲染质量切换渲染feature等,这让我们在遇到关键节点的时候,即使没有开发完所有feature也能够有最后手段进行自救。

不要急着定目标,因为你定不出合理的目标,反而容易陷入路径依赖的陷阱(问问别的项目目标是什么,要不我们也这么做吧)。要做的是建立目标体系,自动化体系,以及上线所必须的优化feature。

早期测试:不得不使用的临时手段

不用追求设备覆盖率,但求流畅游玩,达到目标即可不要强求。

不同的游戏,往往发布节奏也不一样,这取决于制作人的想法和市场情况。但是当我们还没有完全开发完基建和美术资产的时候,如果明确短期时间节点上存在对外测试的情况,那我们必须明确我们测试的目的是什么:是验证玩法吗,性能重要吗,目标机型是什么。

确定这些问题的时候必须实事求是,到底我们能做到什么程度,如果我们只是为了验证玩法,则完全没有必要为了低端设备的玩家而大动干戈,选择合理的目标设备就可以了。但是需要注意的是,即使选择了一些相对合理的目标设备,我们依旧可能存在在目标设备上大量卡顿、内存过高的问题,这个时候实际上我们依旧需要用临时手段来让我们的性能变得更符合测试的要求。

这个时候只要目标设备往上提,内存和帧率往往不会成为太大问题,但卡顿是绝对需要注意的问题,建议这个阶段不要开放过高的帧率,尽量让卡顿隐藏在frametime中,反而会比高帧率来得更流畅,早期测试想要清理掉大部分卡顿非常困难,特别是缺乏一些优化基建的时候。

这个时候上一章提到的scalable的重要性便体现了出来,虽然实际可能会比最终feature落地之后使用更有损的优化,但是也比玩家完全没办法玩要好。

对于程序来说,上线前关掉或者简化一些功能是相对比较简单的方式避免过高的开销。而对于美术而言临时优化却是非常痛苦的一件事情,可能需要针对现有的非正式资产进行减面或者是临时实现一些功能,比如在GameObject上临时挂上一些脚本而不是正式调度流程来实现一些功能。

不管黑猫白猫,能抓到老鼠的就是好猫。各个部门也是各凭本事。

不得不说,对于几乎所有项目来说,早期测试永远存在着遗憾和妥协,完美几乎是不可能做到的,如果已经性能完美那说明项目快黄了,需求的迭代速度还没性能优化得速度快(笑)。

铺量阶段

开始有明确的自我认知,蛋糕分清楚,子目标填充和明确,明确指标并且提高自动化率。

当项目进入铺量阶段,关键的优化feature往往已经落地,剩下在排期内的优化feature是锦上添花,而非上线的必须项。在我们拥有第一个成熟case的情况下我们可以倒推出所有高重要度的budget。玩家的前几个小时的流程在优化落地之后,将会成为我们打样的目标,例如场景和角色功耗分布的比例,内存占用的比例,每个角色、场景的基本参数大概是怎么样的,drawcall该是多少、功耗是多少,应该明确。在开发后续内容的过程中有种绝对重要的参考性,最重要的参数在没有重大性能优化feature的情况下不再轻易发生改变。

在明确指标实际数值之后,我们会将数值实装到各个自动化的平台:

  • 单元测试、后验将自动化检查单个资产合理性
  • 静态动态热力图将自动化检查场景的布设合理性
  • 玩法case将自动化检查关键玩法中业务的合理性

在铺量的过程当中不断发现新的性能问题,不断将性能问题转化为具体的检查规则和数据填入到自动化平台,自动化的程度越高,老问题越少,有更多的时间投入到通用优化,留出时间进行通用优化。

具体该怎么落地我们在发现问题章节当中讨论。

当有了足够的通用优化,实现我们的budget越来越轻松(当然一些游戏资产精度每个版本会涨,所以并不一定和我说的一样),策划的想法也日新月异,我们的游戏就像宝可梦一样,该进化了。

重大影响性能feature降临

拥抱变化,迎接挑战,小步快走,同时调整目标,不要在蠢问题和老问题上花太多时间。

很多游戏从上线的第一天开始,就停止了进化,几年如一日的玩法,基本上性能优化会变成一个枯燥乏味的工作。但是近几年的国内游戏日新月异,一年内几次开服的盛况也是空前,一个游戏在一年前和一年后可能完全是两个不一样的规模,即使没有二次开服这么盛大,做一个大版本的活动往往也可能伴随着重大的性能风险。很显然,旧有的目标不再满足我们的需求。

在制作组出现这个想法的时候就需要第一时间和性能优化团队进行沟通,例如:一个没有大世界要素的游戏,突然需要支持巨大的地图。或者是已经有大世界的游戏需要支持更复杂的地形,更高的密度,从只能地上走路到可以上天入地。

我们必须估计如果需要实现目标需求会和当前的哪些budget相悖,例如:如果需要新的大世界,则需要支持更高效的streaming,场景的budget或者测试方法需要重新制定。如果有新的动作模组,那么相关的动画内存,cpu耗时是否需要调整,或者是用其他的优化挤出余量来支持新的功能。

做一个新的重大feature和做一个新游戏一样,尽可能早地跑起来第一个case,进行性能摸底。

性能摸底,提出性能优化feature,验收迭代。直到能够满足先前的性能源头目标。

这里大概率遇到痛苦的点是:我同时需要兼顾项目维护当前的性能优化,又需要有人推进新的性能feature和流程。

要实现这一目标的前提:

  • 充足的自动化来解决老问题,人力解放来解决新问题
  • 充足的人力来增加通用优化,另外一批人解决经常出现的老问题
  • 这两个都没有,那就加班吧

对于中大型项目而言,自动化绝对是非常高优先级的事项。

可惜总有一些公司的项目负责人会认为,多请几个外包QA就可以解决这个问题了。

外包QA的工作往往依赖个人的经验,人类的记忆和经验是不可靠的。而自动化Case和规则则能够学习和迭代,以前犯过的错经过迭代不再犯,规则也层层包浆,过个三五年,这不是人的脑容量能够处理的,一旦发现问题可以立刻反馈。如果一个人每天做的事情差不多,便容易发生流动,而人员一旦流动,先前的很多积累都会流失,踩过的坑可能还要反复踩。

哎!再苦一苦牛马!

总结

虽然每个项目的经历不同,所拥有的人力也不同,能做的事情也不同。大项目有大项目的做法,小项目有小项目的做法。但框架我认为却是相同的。

  • 立项:确定项目的定位,确定最初的机型目标。
  • 早期:了解你目标的组成部分,开始组织目标地图,知道蛋糕有哪些部分,但具体蛋糕怎么分待定。
  • 内部测试:不用追求设备覆盖率,但求流畅游玩,达到目标即可不要强求。
  • 铺量上线:开始有明确的自我认知,蛋糕分清楚,子目标填充和明确,明确指标并且提高自动化率。
  • 持续进化:拥抱变化,迎接挑战,小步快走,同时调整目标,不要在蠢问题和老问题上花太多时间。

对于小项目,程序负责人需要知道自己的方向,团队能力的上限,不需要过于复杂的自动化,明确目标设备之后做好最简单的性能监控,发现项目最大的瓶颈点,逐个击破,用最小的成本解决最大的瓶颈点。

对于大项目而言,则需要体系化的性能优化体系,明确目标设备和主目标,细子分目标并且落实到各个不同的团队部门,将目标深入到资产制作管线当中。建立完善的自动化体系,上百人的项目每天都充斥各种问题,不要让蠢问题和老问题拖你的后腿,让自动化监控和出警解放你的人力。把更多的人力投入到通用优化,得到更多的性能资源空闲,加速项目的进化才能让项目在如此激烈的竞争环境下得到一些优势。

发表回复

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