添加 L1 缓存大小的数组.大数组绝对比短数组快

Adding arrays of L1 cache size. Large arrays are absolute faster than short arrays

本文关键字:数组 L1 缓存 添加      更新时间:2023-10-16

早上好,

我编写了以下程序来添加两个数组:

#include<iostream>
#define line 32
inline void add(float a[], float b[]){
  for (int i=0; i<line; i++){a[i]+=b[i];}
}
int main(){
float a[line]; for (int i=0; i<line; i++){a[i]=0.;}
float b[line]; for (int i=0; i<line; i++){b[i]=0.;}
for (int i=0; i<1024*1024*512; i++){add(a,b);} //Add arrays several times
for (int i=0; i<line; i++){std::cout << a[i] << std::endl;} //Print arrays, else -05 optimize it away.
}

我编译了它(g ++版本4.8.4/我的硬件较旧)

 g++ add.c++ -O5 -o Test

并运行它

time ./Test

如果 line=32,则需要 1.3 秒

如果 line=16,则需要 2.3 秒

我尝试了几次,运行时总是相同的(所以它是稳定的。我知道,一个大数组可以相对较快(矢量处理器等),但我不明白为什么它绝对更快。我编写这个程序是为了弄清楚如何实现峰值性能。我的问题:CPU 中发生了什么,我该如何改进它?

您的编译器将能够非常轻松地展开具有硬编码限制(如 16/32/64)的循环。展开"32 次"循环并使用 AVX 可能会导致恰好增加 4 个 AVX。这将比"16 倍"循环更快,后者会导致 2 个 AVX 添加,因为当分支碰巧在您的每条"线路"上运行时,可能会出现管道停滞(除非您在诸如 xeon 之类的东西上运行可以推测性地执行多条路径)。

除非仔细操作,否则微基准测试可能会产生误导,因此您应该始终查看生成的程序集。由于您的基准测试只是一遍又一遍地撞击相同的内存,您应该考虑这是否真的代表了生产中将发生的情况。

从你的编译语句中可以清楚地看出,你正在使用O5 optimization来编译代码。

众所周知,除了O2 optimization所有其他变体都不稳定。我建议您不要将它们用于测试目的,最重要的是它没有很好地定义。

这里可能有很多条件。就像O5 optimization一样,直到您的程序消耗大量内存或其内部优化算法检测到计算压力过大之前,它实际上可能无法工作。就像我说的O5 optimization没有明确的定义和稳定。当我编码时,我面临这种类型的问题并停止做任何O.x optimization

我希望这有所帮助。