首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >考虑缓存一致性的高性能应用C++按值传递与参照传递的数学结构类

考虑缓存一致性的高性能应用C++按值传递与参照传递的数学结构类
EN

Stack Overflow用户
提问于 2020-09-08 00:10:41
回答 1查看 276关注 0票数 2

对于许多高性能的应用程序,如游戏引擎或金融软件,考虑缓存一致性、内存布局和缓存丢失是保持平滑性能的关键。随着C++标准的发展,特别是随着Move语义C++14的引入,数学类的值传递和引用传递的界限越来越不清晰。

考虑一下常见的吊舱 Vector3类:

代码语言:javascript
复制
class Vector3
{
public:
   float32 x;
   float32 y;
   float32 z;
   // Implementation Functions below (all non-virtual)...
}

这是游戏开发中最常用的数学结构。它是一个非虚拟,12字节大小的类,甚至64位,因为我们显式地使用IEEE float32,它每个浮动使用4字节。我的问题如下-在决定通过数值或参考的数学课程时,高性能应用程序使用的一般最佳实践准则是什么?

在回答这个问题时,有几件事需要考虑:

  • 假定默认构造函数不初始化任何值是安全的。
  • 假设任何POD数学结构都不使用超过1D的数组是安全的。
  • 显然,大多数人按值传递4-8字节的POD常数,因此似乎没有太多的争论。
  • 当此向量是堆栈中的类成员变量和局部变量时,会发生什么情况?如果使用通过引用传递,那么它将使用类上变量的内存地址,而不是堆栈上本地对象的内存地址。用例重要吗?在使用PBR的情况下,这种差异会导致更多的缓存丢失吗?
  • 使用或不使用SIMD的情况如何?
  • 移动语义编译器优化如何?我已经注意到,当切换到C++14时,当按值传递相同的向量时,编译器通常会使用move语义,特别是当它是const时。我通过仔细阅读装配分解来观察这一点。
  • 当在这些数学结构中使用pass值和传递引用时,const是否对编译器优化产生了很大影响?见上述要点

鉴于以上所述,什么时候使用pass值与引用现代C++编译器(C++14及以上)来减少缓存丢失并促进缓存一致性,有什么好的指导方针?在什么情况下,可能有人会说这个POD数学结构太大,不能通过值传递,比如一个4v4仿射变换矩阵,它的大小是64个字节,假设使用了float32。在做出这个决定时,向量,或者更确切地说是任何小的POD数学结构,是否声明在堆栈上,而不是作为成员变量被引用?

我希望有人能提供一些分析和洞察力,以便为上述情况建立一个良好的现代最佳实践指南。我相信,随着C++标准的发展,对于何时将PBR用于POD类,尤其是在最大限度地减少缓存丢失方面,这条线变得越来越模糊。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-08 05:26:09

我认为问题的标题是关于按值传递还是按引用传递的选择,尽管听起来你更广泛地追求的是高效地传递3D向量和其他普通吊舱的最佳实践。传递数据是基本的,并且与编程范例交织在一起,因此对于最佳的实现方法还没有达成共识。除了性能之外,还需要权衡代码的可读性、灵活性和可移植性,以决定在给定应用程序中采用哪种方法。

尽管如此,近年来,“面向数据的设计”已经成为面向对象编程的一种流行替代品,尤其是在视频游戏开发中。其基本思想是考虑程序需要处理的数据,以及如何将所有这些数据组织在内存中,以获得良好的缓存局部性和计算性能。在2014年的CppCon:Mike的“面向数据的设计与C++”上有一个很好的讨论。

例如,在您的Vector3示例中,通常情况是,程序不仅有一个三维向量,而且很多三维向量都是以相同的方式处理的,比如说,所有的三维向量都经过相同的几何变换。面向数据的设计表明,将向量连续地放置在内存中,并在批处理操作中将它们全部转换在一起是一个好主意。这改善了缓存,并创造了利用SIMD指令的机会。您可以使用特征C++线性代数库实现此示例。这些矢量可以用3xN形状的Eigen::Matrix<float, 3, Eigen::Dynamic>表示来存储N个矢量,然后使用本征的SIMD加速运算进行操作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63785589

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档