我一直在运行某些算法的基准测试并分析它们的内存使用和效率(L1 / L2 / TLB访问和未命中),并且一些结果对我来说非常有趣。
考虑到包容性缓存层次结构(L1和L2缓存), L1缓存未命中数是否应该与 L2缓存访问次数一致?我发现的一个解释是TLB相关:当TLB中没有映射虚拟地址时,系统会自动跳过某些缓存级别的搜索。 这看起来合法吗?
答案 0 :(得分:9)
首先,包容性缓存层次结构可能并不像您假设的那么常见。例如,我不认为任何当前的英特尔处理器 - 不是Nehalem,而不是Sandybridge,可能是Atoms--都有一个L1包含在L2中。 (然而,Nehalem和Sandybridge确实将L1和L2都包含在L3中;使用英特尔目前的术语,FLC和MLC在LLC中。)
但是,这并不一定重要。在大多数缓存层次结构中,如果您有L1缓存未命中,那么可能会在L2中查找该未命中。无论是否具有包容性都无关紧要。如果不这样做,你必须要有一些东西告诉你,你关心的数据(可能)不在L2中,你不需要看。虽然我设计了协议和内存类型,但这样做 - 例如只在L1中而不是在L2中缓存的内存类型,对于像图形这样的东西很有用,你可以在L1中获得组合的好处,但是你在多个阵列上反复扫描,所以在L2中缓存并不是一个好主意。我目前还不知道有人发货。
无论如何,这里有一些原因可以解释为什么L1缓存未命中数可能不等于L2缓存访问次数。
您没有说明您正在使用哪种系统 - 我知道我的答案适用于Nehalem和Sandybridge等Intel x86,其EMON性能事件监控允许您计算诸如L1和L2缓存未命中等内容。它可能也适用于任何具有硬件性能计数器的现代微处理器,用于缓存未命中,例如ARM和Power上的那些。
大多数现代微处理器并没有在第一次缓存未命中时停止,而是继续尝试做额外的工作。这通常被称为推测性执行。此外,处理器可能是有序的或无序的,但是虽然后者可能会给你更多的L1未命中数和L2访问次数之间的差异,但是没有必要 - 你甚至可以在以下情况下获得这种行为 - 订单处理器。
简短回答:许多这些推测性内存访问将在同一个内存位置。他们将被压扁并合并。
性能事件“L1缓存未命中”可能[*]计算错过L1缓存的(推测)指令的数量。然后分配一个硬件数据结构,在英特尔称为填充缓冲区,在其他地方分配一个未命中状态处理寄存器。对同一高速缓存行的后续高速缓存未命中将丢失L1高速缓存但是命中填充缓冲区,并且将被压扁。只有其中一个,通常是第一个将被发送到L2,并计为L2访问。)
顺便说一句,可能会有一个性能事件:Squashed_Cache_Misses。
可能还有性能事件L1_Cache_Misses_Retired。但这可能会有所不足,因为推测可能会将数据拉入缓存,并且退休时的缓存未命中可能永远不会发生。
([*]顺便说一下,当我在这里说“可能”时,我的意思是“在我帮助设计的机器上。”几乎肯定。我可能要检查定义,看看RTL,但我会如果没有,我会感到非常惊讶。几乎可以保证。)
E.g。想象你正在访问字节A [0],A [1],A [2],... A [63],A [64],......
如果A [0]的地址等于零模64,那么A [0] .. A [63]将在具有64字节高速缓存行的机器上的同一高速缓存行中。如果使用这些代码的代码很简单,很可能所有这些都可以推测性地发布。 QED:64个推测性内存访问,64个L1缓存未命中,但只有一个L2内存访问。
(顺便说一句,不要指望数字非常干净。每次L2访问可能无法获得64次L1访问。)
更多可能性:
如果L2访问次数大于L1缓存未命中数(我几乎从未见过它,但有可能),则可能存在令硬件预取混淆的内存访问模式。硬件预取程序尝试预测您将需要哪些缓存行。 如果预取程序预测错误,它可能会获取您实际上不需要的缓存行。通常会有一个性能无法计算Prefetches_from_L2或Prefetches_from_Memory。
某些计算机可能会在发送到L2之前取消导致L1缓存未命中的推测访问。但是,我不知道英特尔会这样做。
答案 1 :(得分:1)
数据高速缓存的写入策略确定存储命中是仅将其数据写入该高速缓存(回写或回写)还是高速缓存层次结构的后续级别(直写)。 因此,在直写L1-D缓存中命中的存储也会将其数据写入L2缓存。
这可能是L2访问的另一个来源,它不是来自L1缓存未命中。