找回密码
 立即注册
查看: 1538|回复: 20

大多数游戏做多核优化的难点是什么?

[复制链接]
发表于 2021-2-26 10:54 | 显示全部楼层 |阅读模式
P社全家,钢铁雄心啊,群星什么的,rimworld环世界,石炉,监狱设计师等等...  我发现在玩这些游戏时候,都是一核有难 多核围观
发表于 2021-2-26 10:55 | 显示全部楼层
由于题主似乎不是太了解游戏开发的编程方面,以下我只是简单概括的谈一下。
游戏在某方面来说,可以是相当复杂的软件。一个游戏可能涉及许多系统/子系统共同运作,例如常见的有游戏性、图形、音频、输入、动画、物理、人工智能、资源管理、内存管理、数学库等等。这些系统会彼此依赖,例如游戏性系统想要知道玩家角色的头部位置,需要从动画系统取得,而动画系统也要知道当时角色的动作状态,这个状态又依赖于游戏逻辑。如果要用多核并行处理一些任务,需要考虑任务之间的依赖性。并行时需要任务之间不互相依赖。如果游戏性本身需要并行,要考虑所有依赖性问题,然后用某种框架来编写游戏逻辑。另一解决方法之一,有时候会使用异步方式去处理,例如在这一个时步做射线检测,发起请求后,我们可能在下一个时步才获取结果。缺点除了增加了延时,也会令程序变得复杂。
大部分游戏引擎可以透明地做一些并行优化,例如会把动画、物理、渲染等子系统在独立线程或分拆成多任务去执行,令游戏性(通常游戏开发者要做的部分)的开发不需考虑并行问题。而一般来说,游戏性部分也通常不是瓶颈(也许一些RTS类型等多游戏对象的问题较大)。所谓具体问题具体解决,不同游戏遇到「卡顿」、「帧率低」的不流畅体验,需要看问题所在才能优化。例如「卡顿」有可能是一些同步I/O或GC做成的问题,需要针对性进行优化。「帧率低」比较常见是 GPU 的瓶颈,或是 draw-call 太多,都要用不同方法去缓解。如果问题不在 CPU,并行化并不会有什么帮助。另外,如果问题在于内存带宽不足或缓存命中失败,多核是解决不了问题的,反而有可能令整体性能更差。
Windows 10 和游戏中的多线程优化是没什么关系的。说一下 PC 游戏的开发困难。相比游戏机,PC的配置差异很大,核心数量不同,要优化到在不同配置下都有高 CPU 利用率会更困难。GPU就更不用说,高配和低配显卡性能可以相差两个数量级。也有可能一些硬盘慢,串流速度赶不上,出现需要等待 I/O 的情况。相对来说,游戏机的配置比较固定,优化目标清晰,所以一般也能表现得比同等配置的 PC 版好。
关于游戏开发的并行问题,可参考 [1] 的 §7.6(多处理器的游戏循环)和§14.6.4(为并行设计)。
[1] Jason Gregory著,叶劲峰译,《游戏引擎架构》,电子工业出版社,2014。
发表于 2021-2-26 10:59 | 显示全部楼层
很难。
举个不是很恰当地例子吧,假如有1个小朋友来做5道题:
1+2=A
A+5=B
B+10=C
C+2=D
D-4=E
需要计算E是多少,那么,以下情况,哪个速度快?(假设每个小朋友计算速度一样快)
甲:1个小朋友按顺序做下来
乙:5个小朋友同时做,每个小朋友做一题

乙方案,在第一个小朋友做出来之前,第二个小朋友只能等着(因为他不知道A是多少),同理,其他小朋友也是如此,所以效率并没有明显的提高,所以这种情况下,很难优化。

这种情况就是大部分情况下逻辑线程的执行情况。
-----------分割线----------
假如是做这样的题:
1+2=A
3+5=B
8+10=C
18+2=D
20-4=E
很明显,5个小朋友同时做会比一个小朋友做的快的多,这样是可以优化的。

这种情况就是逻辑线程、IO、渲染UI、网络请求等可以异步的操作,大部分游戏/应用都会做这种优化。

----------
举得例子可能不太恰当,理解就好。
发表于 2021-2-26 11:08 | 显示全部楼层
我来尝试一一解答,你的问题因为篇幅我稍作删减处理:
1:疑惑:我在玩很多游戏的时候,发现游戏本身对GPU占用不是很高,很多都是依赖CPU进行处理,但是这些游戏对CPU利用率非常的低(通常都是单线程)。
题主你提到的游戏我虽然都没玩过(因为工作原因现在很少有时间玩游戏),但我还是搜索了一下你说的这几个游戏,她们的画面是这样的(YouTube截图):
Hearts of Iron 4 钢铁雄心4
Rimworld 环世界
Prison Architect 监狱设计师
看到这里相信已经很明显为什么她们的GPU占用率很低了:因为绘制简单。其实CPU和GPU本质上都是获取指令,获取数据,执行指令计算,存储计算结果,画面简单自然计算量低,计算量低以现代的GPU瞬间就算完了,自然占用率低。
AAA大作里通常都是相反的,一般都是GPU是瓶颈。主要原因有两点,其一是图形复杂,其二是其实现在的GPU因为其优秀的并行特性还承载了很多非图形的计算工作,比较流行的大概有在compute shader里做模型的skinning,布料动态模拟,甚至一些AI逻辑。


2:提问:为什么有些厂商在做游戏时候不做多线程/多核优化?这是一件很困难的事情么?
恰恰相反,现在CPU的多线程并行计算在游戏引擎里已经非常普遍了,区别不在于有没有,而在于各团队做到了一个什么程度
在这里无意展开,大概说一下游戏引擎里比较普遍的可以并行去做的系统:比如动画计算,物理引擎中有很大一部分可以并行,碰撞测试,粒子特效,等等等等。
至于难不难么,我认为要分两方面去看:
2.1:多线程系统的实现。这属于引擎底层核心,包括多线程的创建,管理,调度,debug等等方面。这一块必须必须由经验丰富,基础扎实,对自家引擎熟悉的老兵来把握,难度极高,新人做不来。但值得一提的是这种系统开发成本虽然高,但开发完成之后可以持续使用一两个世代。
2.2:多线程系统的应用。底层开发好之后,上层使用就简单多了,比如gameplay程序需要把游戏逻辑切成一块一块可以并行的小块,然后调用底层系统执行。说实话如果底层系统对使用者友善的话,应用起来不难,需要一段时间适应并行思维,但习惯了就好。


3:提问:如果要做多线程/多核优化,应当是怎么样的一种思路?
这个没有固定的方法,也没有绝对的对错,总的原则就是,慢了就想办法优化,从容易优化的地方入手,够用就好
从我使用过的3个AAA引擎来看,大概有两种思路吧:
3.1:Crystal Dynamics和Sledgehammer Games。一个是古墓丽影的引擎,一个是使命召唤的引擎,这两个引擎的实现是,把比较明显的,容易并行的地方做并行,剩下的在一个主线程内继续单线程运行
3.2:顽皮狗。顽皮狗的引擎在并行优化上做得是我见过最极致的引擎,使用的是比线程更轻量级的fiber,细节不展开说,主要思路是多核从一开始就并行,基本上不再存在主线程这个概念。当然了,因为计算任务和任务之间仍然存在依赖性因此等待是无法完全避免的,但并行程度一般来说比我接触过的其它引擎更好(还有更高级的多帧在时间上重叠也不展开说)。
这里给出一个顽皮狗引擎并行化的讲座链接,是我们其中一个技术总监讲的,内容很优秀:
Parallelizing the Naughty Dog Engine Using Fibers


4:提问:win10这部分(多线程)内容优化在哪里?
win10是操作系统,操作系统自身有任务调度和安排的功能,但跟前面说的引擎内并行优化是两码事,有兴趣你可以网上找找操作系统的入门知识介绍,这一块内容很深。


5:总结。
并行这东西说白了就是具体情况具体处理,因为大家的引擎架构,实现,计算需求都不同。如果有一个相对通用的底层系统当然很好,没有的话各厂商也把东西硬做出来了。并行是有代价的,所以计算任务的粒度(granularity)要把握好,否则可能得不偿失,最终目标是取得动态平衡,把你想要的效果在你想要的效率里实现出来。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-2-26 11:17 | 显示全部楼层
多线程/并行化就是难,而多线程最大的难点在于线程间同步/互斥。


比如P社游戏,看起来所有AI的行动都是独立的可以并行,但有个关键问题是,AI的行动需要“更新地图信息”,而每一次行动以后地图都会改变,而这种改变一定会影响其他AI的决策,所以同一个AI的行动可能会有多线程优化的空间,然而不同AI的行动必须是按顺序一个一个来的,所以这把大锁就让P社游戏的多线程优化增加了很大的困难。


P社想要利用多核,比较好的办法是修改游戏机制使其能够允许同时/同步行动。。。然而好好的一个4X怎么能变成rts呢对不对。。。
然而你以为rts多线程就好做了么,当然你一个AI可以一个线程的,然而地图还是全局,还是有锁 。。。而且。。。你造为啥rts有人口限制吧233。


上面只是用P社举个例子,然而不幸的是这个例子对很多游戏都适用:“全局游戏数据”。
很多运算都可以并行,但是对全局游戏数据的修改必须加锁,这个锁你可以费很大力气分成若干把小锁,但是这样的话你又要用很多力气去保证游戏数据的一致性。。。单机游戏有一个好处是CAP定理中的分区容错性不需要考虑,所以多核优化还是可能的,但是最终的性能瓶颈还是会出现在对“全局游戏数据”的读写上。。。而且你总不能为了写个游戏造个dbms出来对吧。


真正能够实现并行的游戏都是在设计上就考虑了并行性的,然而这对设计就提出了很神奇的要求。。。当然游戏行业本来就是戴着性能的镣铐跳舞的。


另外d12的那个“多核心优化”说的是渲染线程,和逻辑线程没啥关系,反而更挤占了逻辑线程能用的核心数。


btw,你拿fps跟4x比你不觉得这对4x不太公平么。fps的逻辑本来就少啊,重点都在物理引擎和渲染上。
发表于 2021-2-26 11:27 | 显示全部楼层
印象中chaos大大在messiah中实现了zero overhead的job system,整个引擎到处都是lockless的,并发度出奇的高,加上上层使用了类似go的语法糖,整个引擎非常漂亮。

但是很可惜,手机上一会就没电了。这是个悲伤的故事(逃
 楼主| 发表于 2021-2-26 11:35 | 显示全部楼层
简单回答一下吧。

1,这确实是非常困难的事。「你行你上」这个回答题主可能觉得不舒服,然而现实就是这样,你试着做做就会发现有多难,这简直是程序员的世纪难题,难到你会发现提出这个问题是可笑的。
2,没有固定思路,必须具体问题具体分析,这也正是多核优化困难的地方。并没有固定的套路去做,有固定套路的地方其实都已经做了,当你真要优化的时候,剩下的必然是那些没有任何通用办法可优化。(顺便说一句,实际上这算不算优化还是存疑的,毕竟多核优化后在计算总量上往往是增加了,额外的代码去协调多任务并行这必然造成计算总量增加。)
3,以我的理解,操作系统不太可能做到这一点。我猜测这实际上指的是让多个核心轮流工作,也就是单一的线程轮流在各个cpu上跑,这样各个cpu均匀发热对散热的控制能更好。实质上单线程还是单线程。要说 cpu 帮你做了小幅度的多核优化还有点可能,操作系统做这事几乎不可能。
发表于 2021-2-26 11:35 | 显示全部楼层
游戏的多线程说白了就是自己实现一套多线程的任务的调度机制,这个任务机制有三大功能
    线程安全,完全无锁,look free自由调度
只有先实现了这个功能,才能在这套基础上的添加功能。
如果在老的引擎上想改成这个基础架构,基本上是,不可能的一件事情。多线程的思维和单线程的线性思维思考方式都不一样。
就算能改成,整个项目组的人也要了解这个功能,如果不熟悉,写出来崩的厉害。
总之,就是难上加难,只用大厂hold 住。


源码: UE的TaskGraph
PPT:  寒霜的FrameGraph
发表于 2021-2-26 11:37 | 显示全部楼层
首先呢,现在一核有难多核围观的现象已经很少了,由于引擎技术的提高,大多数游戏基本能保证所有核心都有工作,但是可能刚工作了一会就休息了,继续围观别的核心干活……
有一个很重要的原因,就是许多游戏玩法逻辑或者渲染逻辑是重度耦合的,而且有明确的先后顺序的。什么叫耦合呢?A必须要用B不然跑不起来,B必须要用C不然跑不起来,这种情况下怎么做多线程优化呢?至于渲染,一般引擎中都管渲染模块叫“渲染管线”,既然是管线,那么就必定要有严格的先后顺序,举个例子吧,下面这幅图是我最近正在设计编写的一套渲染管线,在Unity3D引擎中实现的:
这幅图乍一看有点凌乱,但是其实是很容易懂的,从上到下分别是渲染当前这一帧的每个事件,比如第一个Property Set负责把游戏摄像机信息输入到显存等待使用,第二个部分Geometry负责绘制地形,第三个部分计算灯光,之后是绘制天空,绘制雾效,绘制后处理特效以及抗锯齿等等,之后还会加入许多其他部分,比如粒子特效,透明物体等等等等。。
那么这些功能的依赖关系则是十分严格的,比如所有事件都必须依赖第一个事件完成数据准备,光照的计算需要依赖绘制完毕后的场景,雾效的计算需要依赖绘制完毕后的光照,后处理特效需要等待透明物体绘制完,抗锯齿需要使用上一帧画面进行结合,所以必须等所有绘制都结束……
所以在我开发的过程中,除了一些纯数据类型的处理以及一些底层绘制的处理,几乎没有任何机会使用多线程异步的优化,只能等着它们从前往后一串跑下来。。。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-2-26 11:37 | 显示全部楼层
这个问题的高赞回答已经答的很好了。我再总结一下,尽可能简明清楚。
1、本质前后依赖的问题,不可能被并行处理

咱们先从本质上把握这个问题。
多核的本质就是并行,多人可以同时完成多项工作,或者同一项工作的不同部分,以加快完成速度。
有些问题看似非常复杂,但是易于并行,比如“挖矿”;有些问题简单如1+1,但就是不能并行:
1+2=A
A+5=B
B+10=C
(引用Albert Feng的回答)
数学上不可能的问题,技术再发展1000年都不可能解决。顶多只能是针对具体问题找到临时变通的办法。
(但是游戏逻辑可不是纯粹无法并行处理的问题,大部分问题有办法转化。)
2、为什么有些厂商在做游戏时候不做多线程/多核优化?这是一件很困难的事情么?

这个问题直接给外行人讲有点困难,我从迭代这个角度来说:
大型游戏产品的开发要调用大量人力、财力,对于大型的、具有不确定性的工业生产来说,迭代方法可能是唯一可行的办法。
迭代就是“痛苦”的螺旋前进
“迭代”这次说起来容易,实际上非常“痛苦”。原创性越强的游戏产品,它的开发过程就越是坎坷。比如第一个版本做了10个功能,在第二个版本可能就要砍掉5个。试错本身就是开发过程的一环。
在初期开发时,面对大量不确定性,性能优化的优先级只能降得很低。把东西做出来、效果好,比优化要重要多得多。(从玩家的角度会问:为什么这些破游戏优化很差?其实,有些优化更好的游戏项目却阵亡了。)
而到了游戏项目后期,优化又变成了最重要的事情之一。这时候,多核优化却又很难做:前面提到过,如果前期没有设计好,逻辑已经做成了前后依赖的,那之后就很难改成可并发执行的。
也就是说由于一开始没有想清楚如何提高并发性能,导致后面想改也不好改。其实也可以改,就是推翻多少东西重做的问题,游戏开发者、投资方必须在时间、金钱、效果之间权衡,不可能只关心一方面。
最典型的游戏项目还是《绝地求生》(吃鸡),可以说是九星级玩法,一星级优化。在它推出之后,很多第三方公司包括不限于UE、微软、英伟达都对它的优化贡献过力量,据媒体评价目前优化效果和最初版本相比已经有翻天覆地的提升。(这个说不清是正面例子还是负面例子【笑】)
3、目前的多核优化技术

在众多IT领域中,游戏程序的并发设计是难度最大的问题之一。不过乐观的是,对于多核的利用方法,包括引擎层和逻辑层的,业内也已经积累了很多经验。典型代表为Actor框架、ECS框架等等。目前Unity官方也在大力推进ECS的普及,应该说在未来,多核优化会普遍做的更好。
(上图是Unity ECS官方Demo的截图。成千上万的鱼群飞快游动,普通电脑运行的很轻松。)
从下图可以看到,i5 7500的四个核心的负载非常均匀,有兴趣的同学可以在16线程以上的CPU上进行测试,结果会更有说服力。ECS框架的威力可见一斑。


目前已经有一些游戏项目在多核优化上走的很远了,典型的代表就是暴雪的《守望先锋》。相信相关的引擎和框架技术会快速成熟,到时候无论大公司还是独立开发者,都会从中受益。
4、关于多核优化的思路?

以游戏行业现状来看,多核优化已经是一个比较高阶的技术。就算掌握了ECS,在项目中实践还是有相当多的实际问题需要思考解决。
总之,对于外行人来说只要了解到:将任务分解为适合多核执行,并不是一个简单的、可以一口气解决的问题。其实很多游戏中的具体逻辑,就算不考虑多核优化也并不简单,更不用说在一个限制的条件下实现了。就像是背着沙袋跑步,问题只会成倍增加。
另外类似“Win10是否可以将任务分摊给多个核心?”这类问题在专业角度来看根本不知所云。外行人可以将它当作一个宣传的说法。


最后补充一点:未来,在游戏引擎的层面会考虑多核优化问题,这样一来就算游戏开发者不考虑多核优化,依然能从引擎的优化中部分收益。这也是值得期待的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 19:17 , Processed in 0.098290 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表