向量,矩阵和四元数的缓存性能

Cache performance of vectors, matrices and quaternions

本文关键字:缓存 性能 四元数 向量      更新时间:2023-10-16

我注意到在过去的许多场合,C和c++代码对这些结构使用以下格式:

class Vector3
{
    float components[3];
    //etc.
}
class Matrix4x4
{
    float components[16];
    //etc.
}
class Quaternion
{
    float components[4];
    //etc.
}

我的问题是,这会导致更好的缓存性能比说,这:

class Quaternion
{
    float x;
    float y;
    float z;
    //etc.
}

…既然我假设类成员和函数是在连续的内存空间,无论如何?我目前使用后一种形式,因为我发现它更方便(然而,我也可以在数组形式中看到实际意义,因为它允许人们将轴视为任意依赖于正在执行的操作)。


在听取了受访者的一些建议后,我测试了差异,它实际上比阵列慢——我在帧率上得到了大约3%的差异。我实现了操作符[]将数组访问封装在Vector3中。不确定这是否与它有任何关系,但我怀疑它,因为它应该是内联的。我能看到的唯一因素是我不能再在Vector3(x, y, z)上使用构造函数初始化列表。然而,当我采用原始版本并将其更改为不再使用构造函数初始化器列表时,它的运行速度比以前慢得多(不到0.05%)。不知道,但至少现在我知道原来的方法更快。

这些声明对于内存布局来说是不等价的。

class Quaternion
{
    float components[4];
    //etc.
}

以上保证了元素在内存中是连续的,然而,如果它们是单独的成员,就像上一个例子中一样,编译器允许在它们之间插入填充(例如,以特定的地址模式对齐成员)。

这是否会导致更好或更差的性能主要取决于您的编译器,所以您必须对其进行配置。

我认为这样的优化带来的性能差异是最小的。我想说,对于大多数代码来说,这样的事情属于过早优化。然而,如果你计划在你的结构上做矢量处理,比如通过使用CUDA,结构组合会产生重要的区别。如果感兴趣,请参阅第23页:http://www.eecis.udel.edu/~mpellegr/eleg662-09s/li.pdf

我不确定在这种情况下使用数组时编译器是否能够更好地优化代码(例如,在联合中考虑),但是当使用像OpenGL这样的api时,它可以在调用像

这样的函数时进行优化
void glVertex3fv(const GLfloat* v);

而不是调用

void glVertex3f(GLfloat x, GLfloat y, GLfloat z);

,因为在后一种情况下,每个形参都是按值传递的,而在第一个例子中,只传递指向整个数组的指针,函数可以决定复制什么以及何时复制,这样可以减少不必要的复制操作。