哪个是最佳的块缓存大小还是更小的缓存大小?

时间:2017-10-03 13:59:34

标签: algorithm caching optimization cpu-architecture

给定具有恒定容量和关联性的高速缓存大小,对于给定代码来确定数组元素的平均值,是否需要具有更高块大小的高速缓存?

[来自评论]

检查下面给出的代码来计算数组的平均值:

total = 0; 
for(j=0; j < k; j++) { 
  sub_total = 0; /* Nested loops to avoid overflow */ 
  for(i=0; i < N; i++) { 
    sub_total += A[jN + i]; 
  } 
  total += sub_total/N; 
} 
average = total/k;

3 个答案:

答案 0 :(得分:3)

相关:在典型访问模式的一般情况下,具有一些但有限的空间局部性,较大的行有助于达到某一点。 Hong Jiang和/或Yifeng Zhu(U.Maine)的这些 "Memory Hierarchy: Set-Associative Cache" (powerpoint)幻灯片显示了AMAT(平均内存访问时间)与显示曲线的块大小的关系图,以及还将其分解为未命中惩罚与未命中率(对于一个简单的模型,我认为,对于一个简单的有序CPU来说,它可能会隐藏内存延迟。例如,甚至可能无法管理多个独立的未命中。(错过未命中))

这些幻灯片中有一些很多好东西,包括一个提到循环交换的编译器优化部分(用于修复列主要与行主要顺序的嵌套循环),甚至缓存阻塞以实现更多重用。互联网上的很多东西都是垃圾,但我查看了这些幻灯片,他们对如何设计缓存以及权衡取舍有一些可靠的信息。性能分析的东西对于简单的CPU来说才真正准确,而不像现代的无序CPU可以将某些计算与缓存未命中延迟重叠,因此更短的错失与更少的更长的未命中不同。

此问题的具体答案

所以您关心的唯一工作量是元素的线性遍历?假设良好的硬件预取,这使得缓存行大小几乎与性能无关。 (如此较大的线条表示相同性能的硬件复杂性和功耗使用较少。)

使用软件预取,较大的行意味着较少的预取开销(尽管取决于CPU设计,如果仍然最大化内存带宽,这可能不会损害性能。)

没有任何预取,更大的线/块大小意味着每次需求失败后会有更多的命中。单个遍历的数组具有完美的空间局部性,没有时间局部性。 (实际上,如果数组没有与高速缓存行的开头对齐,和/或在行的中间结束,则在开始/结束时不太完美的空间局部性。)

如果未命中,则必须等到整个行存在于缓存中,然后才能满足导致未命中的负载,这会略微降低较大块的优势。 (但是,高速缓存未命中的大部分延迟是在信令和请求开销中,而不是在它已经开始之后等待突发传输完成。)

更大的块大小意味着具有相同带宽和延迟的飞行中的请求更少,并且有限的并发性是实际CPU中内存带宽的真正限制因素。 (请参阅本答案中有关x86内存带宽的latency-bound platforms部分:具有较高的L3缓存延迟的多核Xeon具有比相同时钟速度的双核或四核更低的单线程带宽。每个核心只有10个线填充缓冲区,用于跟踪未完成的L1未命中,以及bandwidth = concurrency / latency。)

如果您的缓存未命中处理具有早期重启设计,则可以避免这一点额外延迟。 (这很常见,但保罗说theoretically possible to not have it in a CPU design)。导致未命中的负载在到达时立即获取其数据。高速缓存行的其余部分填充&#34;在后台&#34;,希望以后的加载也可以从部分接收的高速缓存行中得到满足。

Critical word first是一个相关的功能,首先发送所需的单词(用于早期重新启动),然后突发传输包裹以传输块的早期单词。在这种情况下,关键字始终是第一个字,因此在早期重启之后不需要特殊的硬件支持。 (上面提到的U. Maine幻灯片首先提到早期重启/关键词,并指出它减少了大型缓存行的未命中惩罚。)

乱序执行CPU(或在有序CPU上的软件流水线操作)可以通过同时具有多个未完成的需求未命中来为您提供相当于HW预取的功能。如果CPU&#34;看到&#34;当前高速缓存行的未命中时,对另一个高速缓存行的负载仍未完成,需求失误可以流水线化,再次隐藏更大或更小行之间的一些差异。

如果线条太小,您就会对L1D可以跟踪的不同线路的未命中线数量进行限制。对于较大的线条或较小的无序窗口,您可能会有一些&#34;松弛&#34;如果没有对下一个缓存行的未完成请求,那么您不会最大化带宽。当你到达缓存行的末尾并且下一行的开始还没有到达时,你就会在管道中为它付出代价,因为它开始得太晚(而ALU执行单元也使用了数据)接近当前缓存行的末尾。)

相关:these slides并未说明较大线与较小线之间的权衡,但看起来相当不错。

答案 1 :(得分:2)

简单的答案是,较大的缓存块将是首选的,因为工作负载没有(数据)时间局部性(没有数据重用),完美的空间局部性(排除第一个块的阵列可能不充分的对齐和不足的大小最后一个块的数组,每个数据块的每个部分都将被使用),以及一个访问流(没有潜在的冲突错过)。

更细微的答案会考虑数组的大小和对齐方式(将使用的第一个和最后一个缓存块的分数以及代表的内存传输时间的一小部分;对于1 GiB数组,甚至是4 KiB块会浪费不到内存带宽的0.0008%),系统首先使用关键字的能力(如果阵列规模适中,并且不支持早期使用数据,因为它变得可用而不是等待要填充的整个块,然后启动开销将消除更大缓存块的大部分预取优势),预取的使用(软件或硬件预取减少了大缓存块的好处,并且此工作负载对预取非常友好) ,存储器系统的配置(例如,使用具有立即页面关闭控制器策略的DRAM将增加更大的高速缓存块的益处,因为每次访问将涉及行激活和行关闭,通常是相同的DRAM库防止等待时间重叠),是否将相同的块大小用于指令和页表访问以及这些访问是否共享高速缓存(指令访问提供第二个&#34;流&#34;这会引入冲突失误;使用两级分层页表的共享缓存TLB未命中将访问两个缓存块),是否使用简单方式预测(更大的块将提高预测准确性,减少错误预测开销),以及可能还有其他因素。

答案 2 :(得分:0)

从您的示例代码中,只要硬件预取程序能够以最大内存吞吐量保持内存流,我们就无法说出任何一种方式。

在随机访问方案中,较短的缓存行可能更好,因为您不需要填充所有行。但是,由于您需要更多标记电路并且可能有更多时间进行比较,因此缓存内存的总量会下降。

因此必须妥协,英特尔选择每行64字节(并取2行),其他人选择每行32字节。