我有这样的课:
//Array of Structures
class Unit
{
public:
float v;
float u;
//And similarly many other variables of float type, upto 10-12 of them.
void update()
{
v+=u;
v=v*i*t;
//And many other equations
}
};
我创建了一个 Unit 类型的对象数组。并调用他们的更新。
int NUM_UNITS = 10000;
void ProcessUpdate()
{
Unit *units = new Unit[NUM_UNITS];
for(int i = 0; i < NUM_UNITS; i++)
{
units[i].update();
}
}
为了加快速度,并可能自动矢量化循环,我将 AoS 转换为数组结构。
//Structure of Arrays:
class Unit
{
public:
Unit(int NUM_UNITS)
{
v = new float[NUM_UNITS];
}
float *v;
float *u;
//Mnay other variables
void update()
{
for(int i = 0; i < NUM_UNITS; i++)
{
v[i]+=u[i];
//Many other equations
}
}
};
当循环无法自动矢量化时,数组结构的性能非常差。对于 50 个单元,SoA 的更新比 AoS 稍快。但是从 100 个单元开始,SoA 比 AoS 慢。在 300 个单位时,SoA 几乎差一倍。在 100K 单位时,SoA 比 AoS 慢 4 倍。虽然缓存可能是 SoA 的一个问题,但我没想到性能差异会如此之大。对 cachegrind 的分析显示两种方法的未命中次数相似。Unit 对象的大小为 48 字节。L1 缓存为 256K,L2 为 1MB,L3 为 8MB。我在这里想念什么?这真的是缓存问题吗?
编辑: 我正在使用 gcc 4.5.2。编译器选项是 -o3 -msse4 -ftree-vectorize。
我在 SoA 中做了另一个实验。我没有动态分配数组,而是在编译时分配了“v”和“u”。当有 100K 个单元时,这提供了比具有动态分配阵列的 SoA 快 10 倍的性能。这里发生了什么事?为什么静态分配的内存和动态分配的内存之间会有如此大的性能差异?