为什么现在大多数缓存行大小设计为 64 字节而不是 32/128 字节?
Why are most cache line sizes designed to be 64 byte instead of 32/128byte now?
我在 linux 中找到,它显示我的 cpu 的缓存行大小是 64 字节,我意识到存在 16/32/128 字节,但大多数 cpu现在设计为 64 字节缓存行大小。为什么不更大或更小?
这是一个权衡。更宽的缓存效率更高(对于给定的缓存大小 area/power),但会导致随机 (non-sequential/strided) 访问的内存流量增加,以及并行缓存之间更多的错误共享争用。
如果您的内存访问模式只需要每个缓存行中的几个字节(例如,沿着广泛分散在内存中的链表进行迭代),则每次访问都需要拉取一个整行进入缓存。因此,将行大小加倍将使内存流量加倍。
如果不同的 CPU,每个都有自己的缓存,正在访问同一缓存行上的内存,则该行将不得不在缓存之间来回“反弹”。避免这种情况意味着在对象之间放置更多的填充。
在这两种情况下,都可以通过将软件调整为需要缓存行大小倍数的块中的内存来避免这些问题。缓存行大小越大,工作越多。
正如 指出的,缓存行的大小涉及权衡。
更大的缓存行减少了每个数据字节的标记位数,提供预取,并以过度预取(浪费带宽和缓存容量)为代价促进更高的带宽(特别是在内存和 L1 接口处),错误共享、更高的未命中延迟(尤其是没有关键字 first/early 重启)和更高的冲突未命中(对于较小的缓存,使用较少的集合,比关联性更多的访问映射到特定集合的可能性增加)。 (更大的缓存行还可以通过保证在更大的地址范围和字节数内命中缓存来提供更好的性能可预测性。)
现代系统不会从这种预取中明显受益;可配置的静态预取器逻辑将提供相同的行为,动态预取可以利用可变资源可用性(例如,缓存容量和内存通道占用)和实用程序,并提供更灵活的预取(例如非单位步幅)。
对于使用 SRAM 存储数据和标签的现代缓存来说,就区域而言,标签开销并不是一个重要的问题。 (IBM 的 Power 和 zArchitecture 实施使用 eDRAM 进行外部高速缓存数据存储,使用 SRAM 存储标签,这使标签相对于数据的面积成本增加了一倍以上。)但是,访问延迟和访问能量受标签阵列大小的影响。对于 L1 缓存,路预测对于较大的缓存行更有效,这既是因为给定缓存容量的缓存行更少,也是因为空间局部性往往适用于甚至超出合理的缓存行大小;只需检查一组标签以获得更广泛或更大数量的访问可以降低更高带宽的成本(这在利用空间局部性并牺牲带宽延迟的 GPU 中最为明显)。对于外部缓存级别,通常使用分阶段标签数据访问(在数据访问开始之前检查标签,以节省能源——尤其是考虑到更高的关联性和缺失率);对于给定的容量,较小的标签阵列可以减少访问能量和延迟(尤其是对于未命中——50% 的命中率并非闻所未闻)。 (请注意,在未命中没有匹配的部分标签的常见情况下,可以使用部分标签来提供早期未命中检测。其他过滤机制也是可能的。)
可以通过使用扇区高速缓存来对抗错误共享,其中为标签的每个地址部分提供了一个以上的有效性(或一致性状态)条目。这在具有更频繁错误共享的较大缓存行和具有较高标记开销的较小缓存行之间提供了一个中间设计点。这也固有地支持减少缓存行填充延迟。对于传统布局,当错误共享或较少空间局部性更常见时,这会导致大型缓存行的大量有效容量成本。对于使用间接的设计,例如提议的非统一缓存架构和 V-Way 缓存,可以通过以更多的间接指针存储为代价,以更细的粒度分配数据存储来减少容量利用率问题。
更大的缓存行提供三个带宽优势。命令开销较小(地址和操作信息几乎是恒定的——地址每增加一倍就小一位)因此每个数据字节的带宽开销较低;这对于许多消息只携带元数据的一致性流量来说更为重要。 (显然,随着更多一致性节点的出现,错误共享可能更容易影响这一优势。)其他每个请求的开销也不随请求大小而扩展(例如,具有随机访问的 DRAM 行激活、完成后关闭行管理) . ECC(或具有重传功能的校验码)对于较大的有效载荷,每个有效载荷字节的开销也较小(这可用于在使用商品宽度内存模块时存储额外的元数据)。
当突发长度固定时,更大的缓存行也有助于更宽的内存接口。增加 DRAM 突发长度有助于提高带宽; DDR5 的突发长度变为 16,推动 DIMM 使用两个 32 位宽的通道,以与 x86 在 64 字节缓存线上的事实上的标准化兼容。虽然这种机会可以被积极地视为增加可用内存级并行性 (MLP)——将通道数量加倍并减少 DRAM 库冲突——当内存的相对延迟更大时(大片上缓存和更快的处理),MLP 更为重要,线程级并行性可用(多核和多线程),乱序执行(和多线程)暴露更多内存访问以隐藏延迟。多核(与多道程序或大型 chunk/stream 通信(例如管道式多线程)相比,与重要的数据内存共享一起使用时)也增加了错误共享的重要性,进一步降低了较大缓存行的好处(超出了较窄的 MLP 好处)频道)。随着较低的(片上)通信延迟和多核处理器的几乎不可避免,多线程编程变得更具吸引力。
对于 L1 缓存,微体系结构(以及 ISA)可能会影响缓存行大小。更高频率的设计有利于较小容量的 L1 缓存,无论是延迟还是访问能量,尤其是对乱序执行或倾斜管道(其中执行管道阶段比地址生成阶段延迟一个或多个阶段)的延迟容忍度更小。
各种权衡的相对大小还取决于工作负载和软件设计。针对从中受益的工作负载的更大缓存容量缓存减少了更大缓存行的过度预取和冲突缺点;更高的关联性减少了冲突劣势,但更可能发生冲突的工作负载不太可能(通常)从空间局部性中受益(并且冲突劣势对于外部缓存级别通常不太重要)。指针追逐工作负载倾向于降低延迟,从而降低容量,支持更小的缓存行(至少在 L1 中)。
软件设计是一个重要因素。避免虚假共享往往会随着缓存行大小的增加而增加填充,从而阻止更大的缓存行。一旦在软件社区中建立了缓存行大小假设(根据 ISA、OS 和 hardware/system 供应商进行了某种程度的隔离),遗留代码和遗留概念化的影响就会限制缓存行大小。
推测:x86 面向通用软件和个人计算机使用(成本和工作负载特征偏向较小的缓存和工作负载可能通常具有较低的空间局部性)可能偏向于选择比 ISA/hardware 供应商更小的缓存行针对对软件开发工作有更高期望的工作站和服务器工作负载。 x86 已标准化 64 字节缓存行,IBM POWER9 使用 128 字节缓存块(分为四个扇区用于 L1 缓存),IBM z15 使用 256 字节缓存块。
(延迟与命中率、访问能量和其他权衡以及软件和程序员的遗留问题似乎导致对 32KiB L1 缓存容量的标准化不太严格。更小或更大的缓存对性能的影响可能更小比错误共享重要,因此软件限制不如缓存行大小重要。)
我在 linux 中找到,它显示我的 cpu 的缓存行大小是 64 字节,我意识到存在 16/32/128 字节,但大多数 cpu现在设计为 64 字节缓存行大小。为什么不更大或更小?
这是一个权衡。更宽的缓存效率更高(对于给定的缓存大小 area/power),但会导致随机 (non-sequential/strided) 访问的内存流量增加,以及并行缓存之间更多的错误共享争用。
如果您的内存访问模式只需要每个缓存行中的几个字节(例如,沿着广泛分散在内存中的链表进行迭代),则每次访问都需要拉取一个整行进入缓存。因此,将行大小加倍将使内存流量加倍。
如果不同的 CPU,每个都有自己的缓存,正在访问同一缓存行上的内存,则该行将不得不在缓存之间来回“反弹”。避免这种情况意味着在对象之间放置更多的填充。
在这两种情况下,都可以通过将软件调整为需要缓存行大小倍数的块中的内存来避免这些问题。缓存行大小越大,工作越多。
正如
更大的缓存行减少了每个数据字节的标记位数,提供预取,并以过度预取(浪费带宽和缓存容量)为代价促进更高的带宽(特别是在内存和 L1 接口处),错误共享、更高的未命中延迟(尤其是没有关键字 first/early 重启)和更高的冲突未命中(对于较小的缓存,使用较少的集合,比关联性更多的访问映射到特定集合的可能性增加)。 (更大的缓存行还可以通过保证在更大的地址范围和字节数内命中缓存来提供更好的性能可预测性。)
现代系统不会从这种预取中明显受益;可配置的静态预取器逻辑将提供相同的行为,动态预取可以利用可变资源可用性(例如,缓存容量和内存通道占用)和实用程序,并提供更灵活的预取(例如非单位步幅)。
对于使用 SRAM 存储数据和标签的现代缓存来说,就区域而言,标签开销并不是一个重要的问题。 (IBM 的 Power 和 zArchitecture 实施使用 eDRAM 进行外部高速缓存数据存储,使用 SRAM 存储标签,这使标签相对于数据的面积成本增加了一倍以上。)但是,访问延迟和访问能量受标签阵列大小的影响。对于 L1 缓存,路预测对于较大的缓存行更有效,这既是因为给定缓存容量的缓存行更少,也是因为空间局部性往往适用于甚至超出合理的缓存行大小;只需检查一组标签以获得更广泛或更大数量的访问可以降低更高带宽的成本(这在利用空间局部性并牺牲带宽延迟的 GPU 中最为明显)。对于外部缓存级别,通常使用分阶段标签数据访问(在数据访问开始之前检查标签,以节省能源——尤其是考虑到更高的关联性和缺失率);对于给定的容量,较小的标签阵列可以减少访问能量和延迟(尤其是对于未命中——50% 的命中率并非闻所未闻)。 (请注意,在未命中没有匹配的部分标签的常见情况下,可以使用部分标签来提供早期未命中检测。其他过滤机制也是可能的。)
可以通过使用扇区高速缓存来对抗错误共享,其中为标签的每个地址部分提供了一个以上的有效性(或一致性状态)条目。这在具有更频繁错误共享的较大缓存行和具有较高标记开销的较小缓存行之间提供了一个中间设计点。这也固有地支持减少缓存行填充延迟。对于传统布局,当错误共享或较少空间局部性更常见时,这会导致大型缓存行的大量有效容量成本。对于使用间接的设计,例如提议的非统一缓存架构和 V-Way 缓存,可以通过以更多的间接指针存储为代价,以更细的粒度分配数据存储来减少容量利用率问题。
更大的缓存行提供三个带宽优势。命令开销较小(地址和操作信息几乎是恒定的——地址每增加一倍就小一位)因此每个数据字节的带宽开销较低;这对于许多消息只携带元数据的一致性流量来说更为重要。 (显然,随着更多一致性节点的出现,错误共享可能更容易影响这一优势。)其他每个请求的开销也不随请求大小而扩展(例如,具有随机访问的 DRAM 行激活、完成后关闭行管理) . ECC(或具有重传功能的校验码)对于较大的有效载荷,每个有效载荷字节的开销也较小(这可用于在使用商品宽度内存模块时存储额外的元数据)。
当突发长度固定时,更大的缓存行也有助于更宽的内存接口。增加 DRAM 突发长度有助于提高带宽; DDR5 的突发长度变为 16,推动 DIMM 使用两个 32 位宽的通道,以与 x86 在 64 字节缓存线上的事实上的标准化兼容。虽然这种机会可以被积极地视为增加可用内存级并行性 (MLP)——将通道数量加倍并减少 DRAM 库冲突——当内存的相对延迟更大时(大片上缓存和更快的处理),MLP 更为重要,线程级并行性可用(多核和多线程),乱序执行(和多线程)暴露更多内存访问以隐藏延迟。多核(与多道程序或大型 chunk/stream 通信(例如管道式多线程)相比,与重要的数据内存共享一起使用时)也增加了错误共享的重要性,进一步降低了较大缓存行的好处(超出了较窄的 MLP 好处)频道)。随着较低的(片上)通信延迟和多核处理器的几乎不可避免,多线程编程变得更具吸引力。
对于 L1 缓存,微体系结构(以及 ISA)可能会影响缓存行大小。更高频率的设计有利于较小容量的 L1 缓存,无论是延迟还是访问能量,尤其是对乱序执行或倾斜管道(其中执行管道阶段比地址生成阶段延迟一个或多个阶段)的延迟容忍度更小。
各种权衡的相对大小还取决于工作负载和软件设计。针对从中受益的工作负载的更大缓存容量缓存减少了更大缓存行的过度预取和冲突缺点;更高的关联性减少了冲突劣势,但更可能发生冲突的工作负载不太可能(通常)从空间局部性中受益(并且冲突劣势对于外部缓存级别通常不太重要)。指针追逐工作负载倾向于降低延迟,从而降低容量,支持更小的缓存行(至少在 L1 中)。
软件设计是一个重要因素。避免虚假共享往往会随着缓存行大小的增加而增加填充,从而阻止更大的缓存行。一旦在软件社区中建立了缓存行大小假设(根据 ISA、OS 和 hardware/system 供应商进行了某种程度的隔离),遗留代码和遗留概念化的影响就会限制缓存行大小。
推测:x86 面向通用软件和个人计算机使用(成本和工作负载特征偏向较小的缓存和工作负载可能通常具有较低的空间局部性)可能偏向于选择比 ISA/hardware 供应商更小的缓存行针对对软件开发工作有更高期望的工作站和服务器工作负载。 x86 已标准化 64 字节缓存行,IBM POWER9 使用 128 字节缓存块(分为四个扇区用于 L1 缓存),IBM z15 使用 256 字节缓存块。
(延迟与命中率、访问能量和其他权衡以及软件和程序员的遗留问题似乎导致对 32KiB L1 缓存容量的标准化不太严格。更小或更大的缓存对性能的影响可能更小比错误共享重要,因此软件限制不如缓存行大小重要。)