对于许多高性能的应用程序,如游戏引擎或金融软件,考虑缓存一致性、内存布局和缓存丢失是保持平滑性能的关键。随着C++标准的发展,特别是随着Move语义和C++14的引入,数学类的值传递和引用传递的界限越来越不清晰。
考虑一下常见的吊舱 Vector3类:
class Vector3
{
public:
float32 x;
float32 y;
float32 z;
// Implementation Functions below (all non-virtual)...
}这是游戏开发中最常用的数学结构。它是一个非虚拟,12字节大小的类,甚至64位,因为我们显式地使用IEEE float32,它每个浮动使用4字节。我的问题如下-在决定通过数值或参考的数学课程时,高性能应用程序使用的一般最佳实践准则是什么?
在回答这个问题时,有几件事需要考虑:
鉴于以上所述,什么时候使用pass值与引用现代C++编译器(C++14及以上)来减少缓存丢失并促进缓存一致性,有什么好的指导方针?在什么情况下,可能有人会说这个POD数学结构太大,不能通过值传递,比如一个4v4仿射变换矩阵,它的大小是64个字节,假设使用了float32。在做出这个决定时,向量,或者更确切地说是任何小的POD数学结构,是否声明在堆栈上,而不是作为成员变量被引用?
我希望有人能提供一些分析和洞察力,以便为上述情况建立一个良好的现代最佳实践指南。我相信,随着C++标准的发展,对于何时将PBR用于POD类,尤其是在最大限度地减少缓存丢失方面,这条线变得越来越模糊。
发布于 2020-09-08 05:26:09
我认为问题的标题是关于按值传递还是按引用传递的选择,尽管听起来你更广泛地追求的是高效地传递3D向量和其他普通吊舱的最佳实践。传递数据是基本的,并且与编程范例交织在一起,因此对于最佳的实现方法还没有达成共识。除了性能之外,还需要权衡代码的可读性、灵活性和可移植性,以决定在给定应用程序中采用哪种方法。
尽管如此,近年来,“面向数据的设计”已经成为面向对象编程的一种流行替代品,尤其是在视频游戏开发中。其基本思想是考虑程序需要处理的数据,以及如何将所有这些数据组织在内存中,以获得良好的缓存局部性和计算性能。在2014年的CppCon:Mike的“面向数据的设计与C++”上有一个很好的讨论。
例如,在您的Vector3示例中,通常情况是,程序不仅有一个三维向量,而且很多三维向量都是以相同的方式处理的,比如说,所有的三维向量都经过相同的几何变换。面向数据的设计表明,将向量连续地放置在内存中,并在批处理操作中将它们全部转换在一起是一个好主意。这改善了缓存,并创造了利用SIMD指令的机会。您可以使用特征C++线性代数库实现此示例。这些矢量可以用3xN形状的Eigen::Matrix<float, 3, Eigen::Dynamic>表示来存储N个矢量,然后使用本征的SIMD加速运算进行操作。
https://stackoverflow.com/questions/63785589
复制相似问题