C 指令缓存加载和逐出规则
我试图了解指令缓存是如何工作的C 指令缓存加载和逐出规则,c,performance,assembly,cpu-cache,micro-architecture,C,Performance,Assembly,Cpu Cache,Micro Architecture,我试图了解指令缓存是如何工作的 在执行代码块时,预取了多少额外的缓存线?它是否考虑了分支预测 如果代码块包含函数调用,函数代码体是按顺序加载的还是在缓存的不同部分中加载的 例如,以下代码片段是否相同 if (condition) { // block of code that handles condition } 及 如果条件很少为真,那么哪种方法可以减少指令序列中的“漏洞” 如果我的第一个示例是经常运行的代码的一部分,并且If条件从来都不是真的,那么If条件的主体最终会被逐出
- 在执行代码块时,预取了多少额外的缓存线?它是否考虑了分支预测
- 如果代码块包含函数调用,函数代码体是按顺序加载的还是在缓存的不同部分中加载的
if (condition) {
// block of code that handles condition
}
及
如果条件很少为真,那么哪种方法可以减少指令序列中的“漏洞”
- 如果我的第一个示例是经常运行的代码的一部分,并且
条件从来都不是真的,那么If
条件的主体最终会被逐出,而代码主体的其余部分保持原样吗If
我假设这些问题没有取决于特定微体系结构的答案。但如果有,我有一个x86-64 Intel Sandy Bridge。事实上,答案在很大程度上取决于微体系结构。这不是x86或任何其他体系结构定义的东西,而是留给设计师在不同的世代中实现和改进 对于沙大桥,你可以找到一个有趣的描述 最相关的部分是- Sandy Bridge的指令获取如上图2所示。分支预测在取指令之前稍早排队,因此所取分支的暂停通常是隐藏的,这是早期在Merom和Nehalem中使用的特性。对32B条指令进行预测,同时从一级指令缓存每次提取16B条指令 一旦知道下一个地址,Sandy Bridge将探测uop缓存(我们将在下一页讨论)和一级指令缓存。一级指令缓存为32KB,64B行,关联性增加到8路,这意味着它实际上是索引和物理标记的。L1 ITLB在小页面的线程之间进行分区,每个线程有专用的大页面。Sandy Bridge为大页面添加了2个条目,使4KB页面(两个线程)的条目总数达到128个,大页面(每个线程)的条目总数达到16个 换句话说,正如图中所示,分支预测是管道的第一步,在指令缓存访问之前。因此,缓存将保存分支预测器预测的地址“跟踪”。如果某个代码片段很难被访问,预测器将避免它,并且随着时间的推移,它将从I-cache中过时。因为分支预测器应该能够处理函数调用,所以代码片段之间应该没有根本的区别 这当然是由于对齐问题(I-cache有64B行,不能有部分数据,因此内联代码实际上可能比函数调用造成更多无用的开销,尽管两者都是有界的),当然也是由于错误的预测。
也有可能其他硬件预取器正在工作,可能会将数据提取到其他级别,但这并不是官方披露的内容(指南仅提到一些二级缓存预取,可能有助于减少延迟,而不会影响一级缓存)。还要注意的是,Sandy bridge有一个uop缓存,它可能会增加更多缓存(但也更复杂)。现代评测编译器肯定会尝试将热路径打包到尽可能少的缓存块中。我建议您阅读函数内联。@EOF-我指的是函数没有内联的情况。@BenVoigt-在这种情况下,编译器不知道该块是否是热路径的一部分,可以使用
gcc
和clang
扩展来标记不太可能
等情况。查看此帖子:
if (condition) {
handle_condition(); // function that handles the condition
}