Wikipedia 文章的概览图描述了Nehalem(第一个 cpu 品牌为“Core i7”)每个内核具有 256 KByte 的 L2 Cache。
我不明白您在这里所说的“银行”一词是什么意思。Nehalem 的高速缓存是 8 路关联的,每个高速缓存行有 64 位(8 字节)。
这意味着对于缓存的每次读/写访问,都会传输 8 个字节的数据,这很好地对应于所有虚拟地址都有 8 个字节的 64 位架构。因此,每次必须从内存中检索或存储地址时,都必须传输 8 个字节,因此以这种方式在缓存中设计单个条目是很自然的。(其他缓存大小也有意义,具体取决于应用程序:例如更大的数据缓存用于矢量处理单元)。
x-way 关联性决定了内存地址与该地址中的信息可以存储在高速缓存中的位置之间的关系。术语“8路关联”是指存储在某个内存地址的数据可以保存在8个不同的高速缓存行中。缓存有一个地址比较机制来选择一种方式内的匹配条目,以及一些替换策略来决定使用哪一种方式——可能会驱逐以前的有效值。
您对“银行”一词的使用可能是指这种 8 路关联性的一个这样的“集合”。因此,您的问题的答案可能是“8”。再说一次,每个核心有一个 L2 缓存,并且每个都有这种结构。
您对同时访问的假设也是有效的。它记录在例如 ARM 的 Cortax A15 中
。但是,是否以及如何独立访问这些缓存组或组是任何人的猜测。Wikipedia 图显示了 L1 数据缓存和 L2 缓存之间的 256 位总线。这可能意味着可以独立访问 4 种方式(4 * 64 = 256,但更有可能的是在任何给定时间实际上只有一个内存加载/存储被传输,并且较慢的 L2 缓存仅同时提供 4 个缓存行到更快的 L1 缓存可以称为突发。
可以在英特尔页面上找到的系统架构手册第 2.2.6 章列出了后来的 Sandy Bridge 改进,强调“每个周期两个负载和一个存储的内部带宽” ,这一事实支持了这一假设。因此,SandyBridge 之前的 CPU 应该有较少数量的并发加载/存储。
请注意,“飞行中”加载/存储和传输的实际数据存在差异。“进行中”是当前正在执行的那些操作。在所有缓存报告未命中后可能需要等待内存产生数据的负载的情况下。因此,您可以并行处理许多负载,但您仍然可以让任意两个缓存之间的数据总线在任何给定时间仅使用一次。上述 SandyBridge 改进实际上将数据总线扩大到两个负载和一个存储同时传输数据,这是 Nehalem(一种“tock”,或 Sandy Bridge 之前的一种架构)无法做到的。
在某些情况下,您的直觉是不正确的:
- 超线程和多线程通常允许 cpu 每个周期执行多个语句。(Nehalem,第 2.2.5 章:“为每个内核提供两个硬件线程(逻辑处理器)。利用 4-wide 执行引擎”。因此,支持多个并发加载/存储到 L1 缓存是有意义的。
- L2 缓存同时为 L1 数据和 L1 指令缓存提供服务——你在这方面是正确的。由于 (1) 中的原因,支持 2 个以上的同时操作可能是有意义的。
- 通常,您可以为 L3 缓存扩大该数量,但实际上这没有意义。我不知道你从哪里得到的数字 32,也许这只是一个猜测。对于任何其他访问点(术语中的“银行”),您必须具有地址解码器、标记数组(用于处理与缓存行的地址比较、替换策略和任何缓存数据标志(脏位等))。因此,每个访问端口都需要一些晶体管开销,因此需要硅片的面积和功率。每个存在的端口也会减慢缓存访问速度,即使它没有被使用。(细节超出了这个答案的范围)。所以这是一个微妙的设计决定,通常 32 是很高的。通常对于 cpu 内的任何类型的内存,数字范围从 1 到 6-8 个读取端口和 1 到 2-4 个写入端口。当然,也可能有例外。
关于您关于软件优化的观点:如果您是低级硬件/固件开发人员,请担心。否则,只需遵循高级想法:如果可以,请将最内部的密集操作循环保持较小,以使其适合 L3 缓存。对本地数据进行密集计算的线程数不要超过内核数。如果您确实开始担心这种速度影响,请开始使用匹配的 cpu 开关编译/优化您的代码,并控制机器上的其他任务(甚至是基础设施服务)。
总之:
- Nehalem 的二级缓存是 8 路关联的
- 它支持少于 2 个同时加载和 1 个存储操作,可能只有一个。但是每次加载/存储一次最多可以向/从 L1 数据高速缓存传输 256 位。
- 由于物理设计限制(时序/面积/功率),L3 缓存的同时加载/存储操作数量无法扩展到 32
- 您通常不应该在您的应用程序中过多担心这些细节 - 除非您确定必须这样做(例如在高性能计算中)