CPU 缓存抑制
- 2024-11-04 08:42:00
- admin 原创
- 35
问题描述:
假设我有事实上的标准 x86 CPU,它有 3 级缓存,L1/L2 私有缓存和内核间共享的 L3 缓存。有没有办法分配共享内存,其数据不会缓存在 L1/L2 私有缓存中,而只会缓存在 L3 中?我不想从内存中获取数据(这太昂贵了),但我想试验将共享数据放入和不放入私有缓存时的性能。
假设 L3 在核心之间共享(大概是物理索引缓存),因此对于大量使用的共享数据不会引起任何错误共享或缓存行无效。
任何解决方案(如果存在)都必须以编程方式完成,使用基于英特尔的 CPU(相对较现代的 Xeon 架构(skylake、broadwell))的 C 和/或汇编语言,运行基于 Linux 的操作系统。
编辑:
我有延迟敏感的代码,它使用一种共享内存形式进行同步。数据将位于 L3 中,但读取或写入时将根据缓存包容性策略进入 L1/L2。根据问题的含义,数据将必须无效,从而增加不必要的(我认为)性能损失。我想看看是否可以通过某些页面策略或仅在 L3 中的特殊指令来存储数据。
我知道可以出于安全原因使用特殊内存寄存器来抑制缓存,但这需要 CPL0 权限。
编辑2:
我正在处理在高性能系统上运行数月的并行代码。这些系统是高核心数系统(例如 40-160+ 个核心),它们会定期执行同步,执行时间需要微秒。
解决方案 1:
x86 无法进行绕过或通过 L1D/L2 写入但停止在 L3 的存储。有些 NT 存储会绕过所有缓存。任何强制写回到 L3 的内容也会强制一直写回到内存。(例如一条clwb
指令)。这些是为非易失性 RAM 用例或非相干 DMA 设计的,在这些用例中,将数据提交到实际 RAM 非常重要。
(更新:Tremont / Sapphire Rapids 有cldemote
。早期的硬件将其作为 NOP 运行,因此可以作为提示使用。)
也没有办法绕过 L1D 进行加载(除了使用 SSE4.1 的视频 RAM 等 WC 内存movntdqa
,但在其他类型的内存上并不“特殊”)。 prefetchNTA
根据英特尔的优化手册,可以绕过 L2。(并且在具有非包含 L3 缓存的 Xeon 上绕过 L3。)
在执行读取的内核上进行预取应该很有用,可以触发从其他内核写回到 L3,并传输到您自己的 L1D。但这只有在您想要加载之前准备好地址时才有用。(几十到几百个周期才有用。)
英特尔 CPU 使用共享的包容性L3 缓存作为片上缓存一致性的后盾。2 插槽必须监听另一个插槽,但支持 2P 以上的 Xeon 具有监听过滤器来跟踪移动的缓存行。(这是对 Broadwell Xeon v4 的描述,而不是对 Skylake 和后来的 Xeon Scalable 的重新设计。)
当您读取最近由另一个核心写入的行时,该行在您的 L1D 中始终无效。 L3 包含标签,其标签具有额外信息来跟踪哪个核心具有该行。 (即使该行在某个 L1D 中处于 M 状态,根据正常的 MESI ,这要求它在 L3 中无效,情况也是如此。)因此,在您的缓存未命中检查 L3 标签后,它会触发对具有该行的 L1 的请求,以将其写回 L3 缓存(并可能将其直接发送到需要它的核心)。
Skylake-X (Skylake-AVX512) 没有包含 L3(它具有更大的私有 L2 和更小的 L3),但它仍然具有包含标签的结构来跟踪哪个核心有一条线。它还使用网格而不是环,并且 L3 延迟似乎比 Broadwell 差很多。(尤其是在第一代 Skylake 中;我认为 Ice Lake 和后来的 Xeons 中情况没那么糟糕。)
可能有用:使用直写缓存策略映射共享内存区域中延迟关键部分。我不知道此补丁是否已进入主线 Linux 内核,但请参阅HP 的此补丁:支持 x86 上的直写映射。(正常策略是 WB。)
同样相关:Intel Sandy Bridge 和 AMD Bulldozer 的主内存和缓存性能,深入了解 2 插槽 SnB 上不同起始状态下的缓存行的延迟和带宽。
有关 Intel CPU 上内存带宽的更多信息,请参阅memcpy 的增强型 REP MOVSB,尤其是延迟限制平台部分。(只有 10 个 LFB 会限制单核带宽)。
相关:超级兄弟和非超级兄弟之间生产者-消费者共享内存位置的延迟和吞吐量成本是多少?对于一个线程向某个位置进行垃圾邮件写入而另一个线程读取该位置,有一些实验结果。
请注意,缓存未命中本身并不是唯一的影响。执行加载的核心中的错误推测也会产生很多影响machine_clears.memory_ordering
。(x86 的内存模型是严格有序的,但真正的 CPU 会推测性地提前加载,并在极少数情况下中止,即在加载应该“发生”之前缓存行变为无效。
相关内容:
有没有办法为英特尔 CPU 编写直接核心到核心通信代码?(没有,除了 IPI 中断)
为什么 x86 没有实现直接核心到核心消息传递汇编/CPU 指令? - UIPI 现在存在于 Sapphire Rapids 中:用户空间处理器间中断。
解决方案 2:
您不会找到很好的方法来禁用英特尔 CPU 的 L1 或 L2:事实上,除了一些特定场景之外,例如 Peter 的回答中涵盖的 UC 内存区域(因为它们也不使用 L3,所以会降低您的性能),特别是 L1 从根本上参与了读取和写入。
但是,您可以做的是使用 L1 和 L2 的相当明确的缓存行为来强制驱逐您只想存在于 L3 中的数据。在最近的 Intel 架构中,L1 和 L2 都表现为伪 LRU“标准关联”缓存。我所说的“标准关联”是指您在维基百科或硬件 101课程中读到的缓存结构,其中缓存被分为 2^N 个集合,每个集合具有M
条目(对于M
-way 关联缓存),并且N
使用地址中的连续位来查找集合。
这意味着您可以准确预测哪些缓存行最终会落入同一集合。例如,Skylake 有一个 8 路 32K L1D 和一个 4 路 256K L2。这意味着相距 64K 的缓存行将落入 L1 和 L2 上的同一集合。通常,将大量使用的值落入同一缓存行是一个问题(缓存集争用可能会使您的缓存看起来比实际小得多) - 但在这里您可以利用它来发挥自己的优势!
当您想从 L1 和 L2 中逐出一行时,只需将 8 个或更多值读取或写入到与目标行相距 64K 的其他行中。根据基准测试(或底层应用程序)的结构,您甚至可能不需要虚拟写入:在内部循环中,您可以简单地使用 16 个值,所有值都相隔 64K,直到您访问了其他 15 个值后才返回第一个值。这样,每行都会在您使用之前“自然”被逐出。
请注意,每个核心上的虚拟写入不必相同:每个核心都可以写入“私有”虚拟线,因此不会增加虚拟写入的争用。
一些并发症:
我们在此讨论的地址(当我们说“距离目标地址 64K 处”时)是物理地址。如果您使用的是 4K 页面,您可以通过在 4K 偏移处写入来从 L1 中逐出,但要使其适用于 L2,您需要 64K物理偏移 - 但您无法可靠地获得它,因为每次跨越 4K 页面边界时,您都会写入某个任意物理页面。您可以通过确保对所涉及的缓存行使用 2MB 大页面来解决这个问题。
我说的是“8 个或更多”缓存行需要读取/写入。这是因为缓存可能会使用某种伪 LRU 而不是精确 LRU。您必须进行测试:您可能会发现伪 LRU 的工作方式与您正在使用的模式的精确 LRU 一样,或者您可能会发现需要 8 次以上的写入才能可靠地驱逐。
其他一些注意事项:
您可以使用公开的性能计数器
perf
来确定您在 L1、L2 和 L3 中实际命中的频率,以确保您的技巧有效。L3 通常不是“标准关联缓存”:而是通过散列地址的更多位来查找集合,而不是典型的缓存。散列意味着您最终不会只使用 L3 中的几行:您的目标和虚拟行应该很好地分布在 L3 周围。如果您发现您正在使用未散列的 L3,它应该仍然可以工作(因为 L3 更大,您仍然会分散在缓存集合中) - 但您也必须更加小心可能从 L3 中驱逐。
解决方案 3:
英特尔最近宣布了一条似乎与这个问题相关的新指令。该指令称为 CLDEMOTE。它将数据从较高级别的缓存移动到较低级别的缓存。(可能是从 L1 或 L2 移动到 L3,尽管规范中没有详细说明。)“这可能会加速其他核心对该线路的后续访问......”
解决方案 4:
我认为您不应该(也可能无法)关心,并希望共享内存位于 L3 中。顺便说一句,用户空间C 代码在虚拟地址空间中运行 ,而您的其他核心可能会(并且通常会)运行其他一些不相关的 进程。
硬件和 MMU(由内核配置)将确保 L3 被正确共享。
但我想实验一下将共享数据放入和不放入私有缓存时的性能。
据我对最近的英特尔硬件的了解(相当糟糕),这是不可能的(至少在用户空间中是不可能的)。
也许您可以考虑PREFETCH
机器指令和__builtin_prefetch
GCC 内置指令(它的作用与您想要的相反,它将数据带到更近的缓存中)。 请参阅这个和那个。
顺便说一句,内核执行抢占式调度,因此上下文切换可能随时发生(通常每秒数百次)。当(在上下文切换时)在同一个内核上调度另一个进程时,需要重新配置 MMU(因为每个进程都有自己的虚拟地址空间,并且缓存再次“冷”了)。
您可能对处理器亲和性感兴趣。请参阅sched_setaffinity(2) 。阅读有关实时 Linux 的信息。请参阅sched(7)。并参阅numa(7)。
我完全不确定您所担心的性能影响是否明显(并且我相信在用户空间中这是无法避免的)。
也许您可以考虑将敏感代码移到内核空间(因此具有 CPL0 权限),但这可能需要数月的工作,而且可能不值得付出努力。我甚至不会尝试。
您是否考虑过使用其他完全不同的方法(例如,在您的 GPGPU 中使用 OpenCL 重写它)来处理对延迟敏感的代码?
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件