实体组件系统框架,CPU缓存友好

问题描述 投票:4回答:3

我找不到一个CPU缓存友好的单一框架实现,which means that data on which systems traverse in each game loop cycle is stored in a contiguous memory

让我们看看,系统遍历满足其条件的特定实体,即实体应包含要由X系统处理的A,B,C组件。这意味着我需要一个包含所有实体和组件的连续内存(不是引用,只要引用不是缓存友好的,并且你将有很多缓存未命中),以便尽可能快地从RAM中获取它们在X系统的处理过程中。但是在X系统处理之后,Y系统开始在满足其条件e的一组实体上运行。 g。所有包含A和B的实体。这意味着我们处理与X系统相同的一组实体以及一些具有A和B的其他实体。这意味着我们有两个具有重复数据的连续存储器。首先,由于已知原因,数据复制非常糟糕。而且,这反过来意味着我们需要一个同步,只要您需要从一个向量中找到一些实体并使用另一个向量中包含的新数据进行更新,这同样不再是CPU缓存。

这只是我的一个想法。对于实体组件系统框架数据模型还有其他更现实的想法,但在每个模型中我都可以发现存在同样的问题:在每个游戏循环周期中,由于不连续的数据,您无法阻止大量缓存未命中。

任何人都可以建议一个实现,文章,这个主题的例子,这可以帮助我理解应该使用什么数据模型来获得缓存友好的设计,因为这是游戏性能中最关键的事情之一。

data-modeling entity-system artemis
3个回答
7
投票

我会选择junkdog的答案(因为我写了链接的文章;)),但这是另一个,不同的,接受它:

如果您想要缓存友好的设计,您需要列出:

  1. 你的微处理器
  2. 你的处理器架构
  3. 你的巴士架构
  4. ...
  5. 您的每子框架工作集大小
  6. 所有游戏对象的总工作集/ RAM
  7. 特定游戏中的互连量
  8. ......等

根据这些要求的紧密程度或松散程度,您将对设计做出不同的简单(或难以)决策。游戏开发人员经常重新编写内存管理。他们不这样做是因为他们是愚蠢的,他们这样做是因为每个项目(重新)优化每个项目很容易/值得(这是一个AAA标题?还是AA标题?图形更重要吗?还是网络延迟? ..等)和每个硬件(在PC上,目标硬件每月更改)

我建议你选择一套硬件,创建一个简单的基于ES的游戏,并开始尝试设计一个缓存友好的内存使用 - 并公开记录,使其全部开源,看看你是否可以让其他人感兴趣在运行你的基准测试。


4
投票

Adam Martin / t =机器最近发布了Data Structures for Entity Systems: Contiguous memory - 这是我所知道的唯一专门处理ECS内存布局的文章。

您没有指定语言,但在Java世界中,entreriartemis-odb(通过PackedComponents /也称为免责声明:我的端口)处理Adam所称的“迭代1:每个ComponentType的BigArray”。


2
投票

从理论上讲,我认为这个问题需要付出太多努力来解决,以证明完全解决问题所需的时间。我过去已经花了太多时间在这上面,提出了复杂的解决方案,只能回到更简单的解决方案。我们最大的热点不一定来自实体/组件遍历的非强制缓存未命中。许多系统将为可以加速的特定实体做大量的工作,并且许多组件通常足够大以减少尝试以使多个邻居适合最小数量的方式对它们进行排序的好处。缓存行。

也就是说,如果您只是想对组件进行排序,以便提供缓存友好的内存访问模式,但只针对一个或两个关键系统而不会重叠冲突,也许是针对最小的和最多的组件类型为了帮助最大,这很容易做到这里和那里的一些后处理。我建议您回答热点问题。

通常只是一些基本的排序将帮助您减少所有系统的缓存未命中份额,无论他们处理哪些组件组合。如果你从像这样的代表(我使用的)开始:

enter image description here

经过一段时间运行游戏状态并偶尔删除和添加组件后,您最终得到如下内容:

enter image description here

你可以解开这个烂摊子并按照这样排序:

enter image description here

这可以通过基数排序非常便宜地完成,基于拥有它们的实体索引对元素进行排序作为线性时间的关键。通过一个不错的实现,您通常可以隐藏这一点,而不会注意到帧速率的任何打嗝。我以与上面的数据表不同的方式绘制图表(只是为了清楚哪个组件属于哪个实体),但是同样的想法。只需根据实体索引(实体ID)对组件数组进行基数排序,更新链接(使用并行数组在索引之前/之后映射,并使用实体索引作为键与组件数据一起排序),现在一切一切都很好,整洁,并没有与零星的访问模式纠缠在一起。

这可能不会让对系统特定组合感兴趣的系统成为一组完美连续的组件(如上图所示可能存在一些间隙),但至少它不会在内存中反复往返,可能不得不将内存区域加载到缓存行中,只是为了驱逐它然后再返回并重新加载它,并且在这些情况下很可能会连续访问许多组件。

如果这还不够好,那么给定具有特定实体的特定实体,系统对特定查询感兴趣的组件,您可以将组件排序到数组的顶部,对照系统需要的特定实体,关闭任何差距,现在您对系统具有完美的连续性,专门处理包含运动和渲染组件的实体。这也可以在线性时间内完成后处理,可以在删除并添加许多组件后定期应用。

我从来没有发现过这么远的必要性。我现在只对实体ID进行广义排序,然后通常改进所有系统的访问模式(但没有针对任何给定系统的最佳解决方案)。您的用例可能需要一个最佳版本,但我建议您只关注具有大热点的关键系统,这些热点真正受益于它。

© www.soinside.com 2019 - 2024. All rights reserved.