问题标签 [data-oriented-design]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
unity3d - 使用 ScriptableObjects 动态生成界面
你好伙计们!
目前正在开发一个 AR 应用程序,我正在学习和使用ScriptableObjects。
由于几乎没有编程背景(不到有效的一年),我在某些方面有点挣扎。
我正在尝试为带有交互式元素(又名按钮)的“自制”视频播放器
创建一个框架。
到目前为止,这些按钮(社交媒体、商店、网站)的 sprite 和外部链接都存储在ScriptableObjects 中(帧的 sprite 和视频播放器相关的元素,如 renderTexture 或 videoClip)也是如此。
我想更进一步,通过创建一个预制件让我选择按钮的数量和它们的位置。
例如,假设我必须创建 2 个不同的视频播放器:
- VideoPlayer_A 播放器和框架,以及 3 个按钮(facebook、twitter 和网站)
- VideoPlayer_B 播放器和框架,以及 2 个按钮(facebook 和网站)
考虑到按钮(无论是 1、2 还是 4 -maximum-)必须保持并且在框架顶部具有相等的空间(参见下面的屏幕截图),我该如何实现这一点。最终目标是拥有一个非常模块化的系统,根据我拥有的数据创建框架。
最后一点,我不是要求“已经制定”的解决方案,而是更多地要求实现我所期待的路径。由于我仍在学习,我正在寻找提示,“方法”,但不是直接的解决方案。
谢谢,提前;)
unity3d - 关于ECS(Entity-Component-System)游戏编程中数据访问控制的问题
我们正在使用 ECS(实体-组件-系统)开发游戏。
因为存储在组件中的所有数据都是公开的,所以每个人都可以轻松访问它们。有时有人错误地修改了数据,这会导致很难找到它的错误。
我想制作一个工具来限制访问,然后系统只能访问一些固定组件。我怎样才能做到这一点?
c++ - 使用模板参数包初始化联合
我正在用 ECS 和面向数据的模型编写引擎。我试图避免继承和动态调度,以避免每次update()
调用都破坏缓存。我想出的是:
然后我有一个room
通过内存池保存所有系统和组件的类(管理器)。问题是
编译器抱怨的部分:
我尝试移动椭圆,但没有效果。我实际上想要做的是避免在每一帧上同时使用模板和动态调度,但我需要模板进行初始化。我有一些基本语法错误吗?我完全错过了什么吗?我是面向数据的范式的新手,所以我很乐意接受任何建议。最小的可重现示例:https ://godbolt.org/z/zGAfXS
cpu-cache - CPU缓存是如何工作的(里面问题的完整描述)?
最近,我对面向数据的设计产生了兴趣。到目前为止,我已经阅读了一些关于该主题的文章和出版物。我了解缓存是如何工作的以及它是如何构建的(通常是抽象的)L1、L2、L3,什么是缓存行,什么是 N 路关联,为什么缓存如此高效等等。不幸的是,我在理论上理解这一切,看例子我不能理解它们。另外,我不能将它合二为一,因此我的问题。
我在互联网上遇到了一个例子(http://igoro.com/archive/gallery-of-processor-cache-effects/)(Example3 -> code belowe)。
我的问题:
我不明白为什么性能会随着数组大小的增加而降低(参见链接中的图片)。
毕竟,缓存行是 64 字节(我在某处读到这是大小),所以它应该总是适合 L1。我不明白数据大小和给定缓存级别之间的关系,因为缓存行是 64 字节 + 预取器 256 字节(我在某处读到这是大小),所以一切都适合 L1。(如果缓存线很忙,那么我们可以删除它并添加一个新的需要的缓存线。)。
你可以看到在 32kB 和 4MB 之后明显下降——这是我机器上 L1 和 L2 缓存的大小。
另外:我不明白如何将数据加载到缓存中。我们假设所需的数据不在缓存的任何级别,并且整个缓存是空的。
数据会先加载到 L3,然后再加载到 L2 和 L1(如果合适的话)?还是只达到L1?
我想答案尚不清楚,取决于 CPU 和缓存设计,但如果有人能以某种一般方式描述它,我将不胜感激。
lua - 如何在匹配键上复制嵌套表值
我正在尝试使用纯 Lua 表来实现组合的概念。程序集是较大的表,而原型/类是具有匹配键的较小表,用于修改程序集中的默认值。这一直工作正常,但所有组件都位于实体内的同一级别。现在我正在尝试按类别组织组件,如下所示:
physics = {}
该集合在物理 ( )下只有一个空表
我组装实体的功能是:
(deepcopy 取自 lua 用户 wiki)
但是,因为原型表只包含修改后的值,所以将原型的组件复制到集合中将覆盖集合的默认值。我尝试了递归:
(只是用 assemble_entity 交换了 deepcopy)
我发现的问题是大多数组件返回 nil (而且它的效率明显低下,但并不是每一帧都调用它),所以它肯定是错误的。我以前从来没有搞过递归,所以任何帮助表示赞赏。
我可以通过将每个值存储在原型中来解决这个问题,但是使用组合就没有意义了,而且我还有很多打字工作要做。
caching - Mike Acton 的面向数据的设计 - “每个缓存行的循环”计算是否正确?
我已经看过几次 Mike Acton 关于 DOD 的演讲,以便更好地理解它(这对我来说不是一个容易的话题)。我指的是 CppCon 2014: Mike Acton "Data-Oriented Design and C++" 和GDC 2015: How to Write Code the Compiler Can 实际上 Optimize。
这表明FooUpdateIn占用 12 个字节,但如果您堆叠其中的 32 个字节,您将获得 6 个完全打包的缓存行。FooUpdateOut也是如此,它需要 4 个字节,其中 32 个字节为您提供 2 个完全打包的缓存行。
在UpdateFoos函数中,您可以为每个高速缓存行执行约 5.33 个循环(假设计数确实为 32),然后他继续假设完成的所有数学运算大约需要 40 个周期,这意味着每个高速缓存行将需要大约 213.33 个周期。
现在这就是我感到困惑的地方,他不是忘记了读写吗?尽管他有 2 个完全打包的数据结构,但它们位于不同的内存空间中。在我的脑海里,这就是正在发生的事情:
- 读入[0].m_Velocity[0](根据他之前的幻灯片,这需要大约 200 个周期)
- 由于in[0].m_Velocity[1]和in[0].m_Foo与 in[0].m_Velocity[0]位于同一缓存行中,因此它们的访问是免费的
- 做所有的计算
- 将结果写入out[0].m_Foo - 这是我不知道会发生什么,我假设它会丢弃前一个缓存行(在 1 中获取)并加载新的缓存行以写入结果
- 读入[1].m_Velocity[0],这将再次丢弃另一个缓存行(在 4 中获取)(这将再次花费大约 200 个周期)
- ...
因此,从进出跳出,计算从~ 5.33 循环/缓存行变为0.5 个循环/缓存行,每个缓存行执行 20 个周期。
有人可以解释为什么他不关心读/写吗?或者我的想法有什么问题?
谢谢你。
c++ - 添加未使用的内存时性能下降
当我偶然发现这种奇怪的性能下降时,我正在玩一个简单的“游戏”来测试面向数据设计的不同方面。
我有这个结构来存储游戏船的数据:
然后我有一个更新运动数据的功能:
我的理解是,由于 MoveShips 函数仅使用位置和运动数组,因此 Ships 结构中的额外内存不会影响其性能。但是,当我取消注释 Ships 结构上的注释行时,性能会下降很多。使用 MAX_ENEMY_SHIPS 的当前值,我的计算机中 MoveShips 函数的持续时间从 10-11 毫秒变为 200-210 毫秒。
在这里,我举一个最小的、可重现的例子:
我使用 Visual Studio 编译器,并使用以下命令编译文件:
所以,我的问题是:为什么在添加未使用的内存时,MoveShips 功能的性能下降如此之快?
c++ - 考虑缓存一致性的高性能应用程序的 POD 数学结构类的 C++ 值传递与引用传递选择
对于许多高性能应用程序,例如游戏引擎或金融软件,缓存一致性、内存布局和缓存未命中的考虑对于保持流畅的性能至关重要。随着 C++ 标准的发展,特别是随着Move Semantics和C++14的引入,对于基于 POD 的数学类,何时绘制按值传递与按引用传递的界限变得不太清楚。
考虑常见的POD Vector3 类:
这是游戏开发中最常用的数学结构。它是一个非虚拟的 12 字节大小的类,即使是 64 位,因为我们明确使用 IEEE float32,它每个浮点使用 4 个字节。我的问题如下 -在决定通过价值或参考通过 POD 数学类以用于高性能应用程序时,使用的一般最佳实践指南是什么?
回答这个问题时需要考虑的一些事项:
- 假设默认构造函数没有初始化任何值是安全的
- 可以安全地假设任何 POD 数学结构都没有使用超过一维的数组
- 显然大多数人按值传递 4-8 字节的 POD 常量,所以那里似乎没有太多争论
- 当这个 Vector 是类成员变量而不是堆栈上的局部变量时会发生什么?如果使用引用传递,那么它将使用类上变量的内存地址与堆栈上本地的内存地址。这个用例重要吗?使用 PBR 的这种差异会导致更多的缓存未命中吗?
- 使用或不使用 SIMD 的情况如何?
- 移动语义编译器优化呢?我注意到,当切换到 C++14 时,当链函数调用按值传递相同的向量时,编译器通常会使用移动语义,尤其是当它是 const 时。我通过阅读装配故障观察到这一点
- 当对这些数学结构使用按值传递和按引用传递时,const对编译器优化有很大影响吗?见上一点
鉴于上述情况,对于现代 C++ 编译器(C++14 及更高版本)何时使用按值传递与按引用传递来最小化缓存未命中并提高缓存一致性,有什么好的指导方针?什么时候有人会说这个 POD 数学结构太大而无法按值传递,例如 4v4 仿射变换矩阵,假设使用 float32,其大小为 64 字节。在做出此决定时,在堆栈上声明的 Vector,或者更确切地说是任何小的 POD 数学结构与作为成员变量引用是否重要?
我希望有人可以提供一些分析和见解,以便为上述情况建立一个良好的现代最佳实践指南。我相信随着 C++ 标准的发展,何时将 PBV 与 PBR 用于 POD 类的界限变得更加模糊,尤其是在最大限度地减少缓存未命中方面。
algorithm - 面向数据的设计算法实现
我一直在阅读 Roughgarden 的“Algorithms Illuminated”,我一直很喜欢这本书。但是,它侧重于大 O 运行时分析。而且我已经看到面向数据的设计可以极大地改变算法的运行时间。例如,处理使得最大数量的迭代可以对缓存中的数据进行操作可以显着帮助。(有关详细信息,请参阅 Mike Acton 关于面向数据的设计的演讲。)例如,我知道 FFTW 学习硬件(具有称为智慧的东西)以使其实施更快。
我很想学习在实现算法时如何利用缓存和内存。有没有很好的教科书来学习如何做到这一点?如果没有,是否有学习如何做到这一点的好资源?
谢谢!
terminology - 与“交错”数据布局相反的名称
在计算机图形学和面向数据的设计中,有一个术语“交错”,指的是一种在内存中布局数据的特定方式。因此,对于某些具有和属性的数据a
,内存布局将被称为“交错”。相反的布局是.b
c
a_1, b_1, c_1, a_2, b_2, c_2, ...
a_1, a_2, ..., a_n, b_1, b_2, ..., b_n, c_1, c_2, ..., c_n
是否有一个词可以描述可用于命名类型的其他布局?所以InterleavedBuffer
对???Buffer
。。
我知道“数组结构”(SoA)和“结构数组”(AoS)这两个术语,但两者都不是一个词,我不想使用缩写词,尤其是那些非常相似的缩写词。