36

游戏性能优化杂谈(一)

 3 years ago
source link: https://zhuanlan.zhihu.com/p/267891577
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

最近一年一直在为PS5发售进行软件方面的准备,所以文章写得很少了,大部分时候都只是在知乎上灌水调剂一下心情。

其实日常工作当中,除了诸多杂事之外,比较整块的主要是两部分:

  1. 向国内签约厂商宣讲最新的主机开发技术,并提供相关技术支持
  2. 辅助厂商对项目进行平台特定的性能优化,提高游戏在目标平台上的质量,形成平台优势

其中第二部分的工作,最近一段时间做得比较深入的项目有网易的《荒野行动》,以及米哈游的《原神》。

当然,大部分工作的内容都是受到保密协议的约束,无法在这里公开的。但是一些基本的思路还是可以分享一下。水平有限,难免有所错漏,还望海涵。

首先,如果要对一个游戏项目进行深度的优化,那么团队对于所用引擎的把控能力是十分重要的。上面所提到的两个项目,前者是网易的自研引擎,后者是米哈游魔改的Unity引擎,两个团队各自对于引擎的把控能力都很强,这是能够进行较为深入优化的基本条件。

游戏的性能优化,非常粗略地来说,可以分为3大块:CPU、GPU以及IO。这3部分相对独立,很多时候可以分别进行优化。但是同时,理解这三者互相牵制,在很多时候呈现此消彼长的关系,是非常重要的。

也就是,理论上虽然3者都是效率越高越好(耗时越短越好),但是如果单纯这样的话,一个什么都不做的“空游戏”,性能是最好的。但是这显然没有意义。

所谓的优化,很多时候是需要找到一个全局平衡点:虽然每个要素单独拎出来看似乎都还可以进一步优化,但是整体上却不降反升。只有这个时候,才是真正找到了最优解。

在当代主流电子游戏当中,CPU依然是核心:它负责游戏整体的流程控制,以及资源的调度。GPU是在CPU的指导下进行工作,而IO也只能由CPU驱动(虽然这一点在PS5这个世代已经开始发生改变)

所以,游戏性能优化一般也是先从这里(CPU)入手。因为任何事情,如果要谈快慢,都会需要一个基准。帧率固然是一个绝对基准,通过它你可以很容易发现游戏有没有掉帧——但是,也就到此为止了。

如果需要进一步分析掉帧的原因,则需要引入第二个相对基准,也就是CPU的工作时间周期。

可能对优化工作不熟悉的部分从业者,或者玩家会说:不是吧?如果我发现显卡渲染一帧画面需要的时间比一帧显示的时间长,那么就很明显是GPU端需要优化啊,为什么还要看CPU呢?

其实不然。因为GPU的工作是由CPU提交的。如果CPU工作提交晚了,那么GPU就很可能无法在期限内完成渲染工作。特别是在现代的游戏当中,往往除了传统的CPU到GPU这一条数据路径之外,还存在从GPU到CPU的数据路径:比如遮挡查询、GPU端骨骼蒙皮计算、Grab Pass、Texture LOD FEEDBACK等等。

所以,即便你看到GPU负荷一直居高不下,但是也完全有可能只是在等待CPU的一个信号,并不见得就是渲染工作量太大造成的。事实上,当代游戏很少有能够真正吃满GPU各种资源的,大部分时候都是参杂了各种相互牵制或者低效导致的“相对工作量饱和”

也是因为现代游戏当中CPU与GPU这种密切的联系,现代游戏引擎一般都会在CPU端单独开出一个GPU设备管理线程(也可以称为提交线程或者RHI线程),用来对GPU的活动进行监视。通常,这个线程在CPU端活动的区间,是完全与GPU活动的区间相一致的。所以,只需要在CPU端观察该线程与其它线程,特别是主线程、渲染线程之间的关系,特别是使用同步对象,如mutex、spin lock的地方,是否有按照我们当时设计预期那样的节奏进行工作,往往就可以发现问题。

一个优化到位的游戏,这些线程之间的协作,就应该像一只交响乐队那样,井然有序。由于在游戏引擎层面,所谓的游戏其实就是以某个帧率执行的快速循环。在相当长的一个区间当中,每一次循环执行路径都是极为相似的。所以,每次循环的执行pattern,也是应该是极为相似的。

如果你在你的CPU Profile数据(图)当中,观测到了剧烈的抖动,也就是CPU当中的活动线程忽多忽少,忽快忽慢,那么很可能就是游戏有严重的性能问题,甚至是逻辑错误。

这非常有用。因为通常在一个成熟团队当中,QA团队是会在测试时不间断地抓起profile数据的。这个数据的跨度可能达到数个小时,存储尺寸甚至高达数百GB甚至是1TB以上。当你面对如此庞大的样本数据却要在其中找一个潜在的问题点或者原因的时候,通过这样的方法能够较为快速地看出问题所藏匿的大致所在,会帮你和你的团队节省很多很多时间。

很多人在这个时候就会一下子去看细节,一个微秒一个微秒地去算,然后花大力气优化了半天却发现整体表现毫无改善甚至反而变成负优化,这往往就是落入了局部优化的陷阱。

在这个阶段,比起掐指计算每个微秒,先整体观察帧与帧之间CPU工作情况的变化,确定全局范围最可疑的区间(通过观察CPU上各个相关线程的执行节奏,找到最与众不同的地方),然后再细看这个可疑区间当中具体的执行细节,通过与该区间外的执行情况进行对比,往往能够很快区分出是CPU瓶颈还是GPU瓶颈,亦或是IO。

然后再有针对性地,对最主要的那个因素进行优化,直到该因素退居二线,被别的因素超越的时候。而这个时候,你只重新选择最新的主要因素,继续上面这个迭代过程就好了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK