【发布时间】:2019-08-28 05:44:15
【问题描述】:
我正在尝试建立关于如何编写有效代码以最小化 CPI(每条指令周期)和最小化缓存未命中和后端绑定性能的直觉。我想了解数据局部性和流水线如何交互。
我知道这些事情很多都依赖于特定的硬件,无法肯定地回答。尽管如此,我仍然希望对“典型”台式计算机上“可能”发生的事情有一些合理的指导,使用用 gcc 或 icpc 和 -O2 等通用编译器编译的程序。
考虑以下(人为的)代码。这段代码的目的是设置不同的场景来说明问题。假设一个高速缓存行是 64 字节。 (编辑)-为了澄清,让我们假设在执行 calc 时这些变量都不在任何级别的缓存中。响应正确地指出,如果已经缓存了任何内容,则会影响结果。
class MyClass {
public:
MyClass() {};
inline void calc(const double in);
private:
double x,y[10],z[32],a,b;
};
inline void MyClass:calc(const double in)
{
x = 5 + in;
y[0] = 10 + in;
z[0] = 25 + in;
a = 50 + in;
q = 100 + in;//q is a variable from global scope that is not already in the cache
*pq = 200 + in;//*pq is a pointer from global scope that is not already in the cache
q2 = 300 + in;//q2 is a variable from global scope that is not already in the cache
b = 400 + in;
cout << x << ", " << y[0] << ", " << z[0] << ", " << a << ", " << q << ", " << *pq << ", " << q2 << "," << b;
}
当 calc 运行时,x 和 y[0] 可能在同一个缓存行上,所以 y[0] 会被缓存命中? z[0] 在下一个高速缓存行。但是,它可能会受益于“下一个缓存行”预取并且也是缓存命中? a 是几个缓存行,然后 q 是来自全局范围的变量,位于内存中的某个远程位置。即使 a 是 z[0] 的几条高速缓存行,我们是否应该期望它比 q 更快地加载到处理器中?是否会在更高级别的缓存中进行某种预取,以防止 a 成为完全缓存未命中? q 肯定需要从主内存中提取,因为它来自内存中的远程位置。 *pq 和 q 也需要自己从主内存中提取。
所以我的期望是会发生这样的事情:y[0] 将加载 L1 缓存命中,z[0] 可能加载 L1 或 L2 缓存命中,a 可能是也可能不是 L2 缓存命中,并且 q 肯定是缓存未命中。如果 q 太远以至于它也会导致 TLB 缓存未命中怎么办?那么它会更慢吗?我对这一切的理解正确吗?
流水线如何影响这一点?处理器可以流水线化一系列内存加载,在前一行代码完成之前将 q 从主内存带入高速缓存。因此,在实践中,我们是否会观察到使用位于内存中远程位置的变量 q 的速度减慢?
请注意,calc 是内联的,因此它的指令可能构成调用它的函数中更大的操作链的一部分,我认为这有助于流水线操作。
变量 *pq 如何影响流水线?编译器不知道 *pq 是指向 q2 还是指向 b 的指针。这会影响流水线的功效吗?
最后,我们到达 b。它与 a 位于同一缓存行上。自从我们上次使用 a 以来,我们不得不做几件事,但希望它仍然在 L1 缓存中并且命中?同样,使用指针 *pq(可能指向 b)会影响这里的优化吗?
【问题讨论】:
-
x和y[0]在同一缓存行上。没有这样的保证。MyClass的对象通常不与缓存边界对齐(扩展对齐要求可能会强制这样做)。无论如何,我建议阅读What Every Programmer Should Know About Memory。 -
x 和 y[0] 上的公平点。我应该说它们“可能”在同一个缓存行上。另外,感谢您对阅读的建议。事实上,我昨天读了那篇文章。这个问题的动机是我试图综合我所读到的内容,确认我的理解是正确的,并澄清挥之不去的问题。
-
很公平:)。问题是您一次提出“百万”个问题,而 IMO 中的许多问题无法简单地回答(或者,您可以就这些主题撰写长篇研究文章)。例如,您不能对如何应用硬件预取做出任何假设。它不仅依赖于架构,而且在相同机器代码的执行之间可能存在很大差异。您唯一能做的就是分析您的程序,例如使用硬件计数器。
-
"CPI(每条指令的周期数)" - 我认为你倒退了。人们通常希望最大化 IPC(每时钟指令);-)
-
@JesperJuhl - 感谢您指出错字。我将其更改为“最小化”CPI。
标签: c++ caching cpu hpc cpu-cache