Dra*_*rgy 10 c++ architecture optimization simd
我最近看到了使用手工编写的SIMD内在函数与SoA(数组结构)表示的乐趣.
与我之前的AoS(结构阵列)代码相比,速度的改进,至少对于简单的顺序型流媒体操作而言,在加倍到三倍的速度增加时几乎没有什么惊人的.作为奖励,它简化了逻辑,除了减少内存使用外,还排除了那些棘手的水平操作和混乱组件.
然而,之后有这种苦乐参半的感觉,我意识到他们在代码中使用的是什么PITA,尤其是界面设计.
我经常处理设计中级接口.它们比视频游戏中的级别更高std::vector,但比级别更低Monster.这些对我来说总是一些最笨拙的接口设计和保持稳定,因为它们不足以提供与标准C++容器一样的简单读/写接口.然而,它们不够高级(在界面的入口点缺乏足够的逻辑)来完全隐藏和抽象出底层表示,只提供高级操作.
我认为中级设计的一个例子是可编程粒子系统API,它希望在某些场景下尽可能高效和可扩展,同时便于休闲场景(例如脚本编写者).这样的设计必须提供粒子访问,除非它将为每个可能的算法提供与可想象的粒子相关的方法,否则它必须在某个地方暴露一些原始的SoA细节,让客户从中受益.
设计也不一定要求始终写入SoA类型代码.日常使用量越多,对便利性,简单性,生产率的要求仍然不高.它仅适用于那些罕见的,性能关键的场景,其中底层的SoA表示派上用场.
那么API/lib设计师和大型系统人员如何处理这些需求的平衡呢?
由于SoA消除了任何每个元素的结构,因此当用户nth使用接口的更方便的随机访问部分访问元素时,动态实例化结构/类可能是一个不错的主意吗?也许一个结构包含指向多个SoA数组的第n个条目的指针/引用以进行可变访问?
此外,如果更常见的使用模式是更多随机访问标量逻辑而不是顺序访问SIMD向量逻辑,但SIMD部分被触发足以使其更好地仅使用一个数据结构,可能这种混合SoA表示更好地平衡了所有需求?
struct AoSoA
{
ALIGN16 float x[4];
ALIGN16 float y[4];
ALIGN16 float z[4];
};
ALIGN16 AoSoA elements[n/4];
Run Code Online (Sandbox Code Playgroud)
我不明白高速缓存行的本质,以便知道这种表示是否值得.我注意到它对顺序SIMD情况没有多大帮助,我们可以将全部资源用于一个庞大的算法,但似乎它可能对需要跨组件或随机访问的大量水平逻辑的情况有帮助标量逻辑情况,系统可能同时执行许多其他操作.
无论如何,我一般都在寻求深入了解如何有效地设计具有SoA后端表示的中间层数据结构接口作为实现细节,而不会将复杂性转移到客户端,除非他们真的需要它.
我真的想避免强迫客户端总是在每个使用界面的地方编写SoA类型的代码,除非他们确实需要这种效率,我很好奇如何平衡那些更多的日常随机访问标量使用场景与利用SoA表示的罕见但不太常见的场景.
实际上,我对软件工程的了解不够,无法为您想要做的事情制定一般策略,但特别是对于 AoS 与 SoA 问题,我发现 Robert Strzodka 的这篇论文很有趣:http://asc.ziti.uni- heidelberg.de/sites/default/files/research/papers/public/St11ASX_CUDA.pdf
此抽象的目标是提供一种在 AoS 和 SoA 甚至更复杂的嵌套之间切换的简单方法。作者用它来展示性能如何随着不同的访问模式而变化,而无需触及算法部分,也无需重新编码所有访问的痛苦。
尽管它更关注 GPU 端,但提供的代码也适用于 CPU。