如果我有这门课程:
class MyClass{
short a;
short b;
short c;
};
我有这个代码执行上面的计算:
std::vector<MyClass> vec;
//
for(auto x : vec){
sum = vec.a * (3 + vec.b) / vec.c;
}
我知道CPU只从L1缓存中加载所需的数据,但是当L1缓存从L2缓存中检索数据时,它会加载一个完整的“缓存行”(可能包含几个字节的数据)需要)。
L2缓存从L3缓存加载多少数据,从主内存加载L3缓存?是按页面定义的,如果是这样,这个答案将如何根据不同而不同不同的L2 / L3缓存大小?
答案 0 :(得分:4)
L2和L3缓存还具有小于虚拟内存系统页面的缓存行。 L2和L3缓存行的大小大于或等于L1缓存行大小,并不是L1缓存行大小的两倍。
对于最近的x86处理器,所有缓存都使用相同的64字节缓存行大小。 (早期的奔腾4处理器有64字节的L1缓存线和128字节的L2缓存线。)
IBM的POWER7在L1,L2和L3中使用128字节的缓存块。 (但是,POWER4在L1和L2中使用了128字节的块,但在片外L3中使用了512字节的块。扇形块为子块提供了有效位。对于L2和L3高速缓存,扇区化允许单个相干大小为在整个系统中使用。)
在最后一级缓存中使用更大的缓存行大小可减少标记开销,并有助于处理器与主存储器之间的长突发访问(更长的突发可提供更多带宽并促进更广泛的错误纠正和DRAM芯片冗余),同时允许其他级别缓存和缓存一致性使用较小的块,这减少了带宽使用和容量浪费。 (较大的最后一级缓存块还提供预取效果,由于上一级缓存的容量相对较高,其缓存污染问题不那么严重。但是,硬件预取可以实现相同的效果,同时减少缓存容量的浪费。)使用较小的缓存(例如,典型的L1高速缓存),驱逐更频繁地发生,因此可以利用空间局部性的时间跨度更小(即,更有可能在高速缓存线被驱逐之前仅使用一个较小块中的数据)。较大的高速缓存行还减少了可用块的数量,在某种意义上降低了高速缓存的容量;对于小型缓存而言,这种容量减少尤其成问题。
答案 1 :(得分:3)
这在某种程度上取决于您的平台的ISA和微体系结构。最近基于x86-64的微体系结构在缓存层次结构的所有级别中使用64字节行。
通常,签名短路将需要两个字节,这意味着除了类开销之外,MyClass还需要6个字节。如果您的C ++实现存储了向量&lt;&gt;连续像一个数组,你应该得到每64字节行10个MyClass对象。提供向量&lt;&gt;是合适的长度,你不会加载很多垃圾。
明智的是,由于您以非常可预测的模式访问元素,因此硬件预取器应该启动并获取它预期将来使用的合理数量的数据。这可能会带来比您需要的更多级别的缓存层次结构。它会因芯片而异。