【发布时间】:2012-07-21 22:46:47
【问题描述】:
我有这样的课:
//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 倍的性能。这里发生了什么事?为什么静态分配的内存和动态分配的内存会有这么大的性能差异?
【问题讨论】:
-
你使用什么编译器选项来构建这个?
-
不确定这是否会有所作为,但std::valarray 可能(或可能不会)有帮助。它旨在对整个数组执行数学运算(这样的语法更简洁),但我猜想实现者有特殊的重载来尝试优化这些操作并在可能的情况下进行智能分配等。它可能根本没有帮助,但可能值得一看。
-
在运行基准测试之前将数据集归零会发生什么?未初始化的浮点很有可能是denormalized。您不希望这会破坏您的基准。
标签: c++ c performance caching gcc