CPU 缓存抑制

2024-11-04 08:42:00
admin
原创
35
摘要:问题描述:假设我有事实上的标准 x86 CPU,它有 3 级缓存,L1/L2 私有缓存和内核间共享的 L3 缓存。有没有办法分配共享内存,其数据不会缓存在 L1/L2 私有缓存中,而只会缓存在 L3 中?我不想从内存中获取数据(这太昂贵了),但我想试验将共享数据放入和不放入私有缓存时的性能。假设 L3 在核心...

问题描述:

假设我有事实上的标准 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,尽管规范中没有详细说明。)“这可能会加速其他核心对该线路的后续访问......”

https://software.intel.com/sites/default/files/management/c5/15/architecture-instruction-set-extensions-programming-reference.pdf

解决方案 4:

我认为您不应该(也可能无法)关心,并希望共享内存位于 L3 中。顺便说一句,用户空间C 代码在虚拟地址空间中运行 ,而您的其他核心可能会(并且通常会)运行其他一些不相关的 进程。

硬件和 MMU(由内核配置)将确保 L3 被正确共享。

但我想实验一下将共享数据放入和不放入私有缓存时的性能。

据我对最近的英特尔硬件的了解(相当糟糕),这是不可能的(至少在用户空间中是不可能的)。

也许您可以考虑PREFETCH机器指令和__builtin_prefetchGCC 内置指令(它的作用与您想要的相反,它将数据带到更近的缓存中)。 请参阅这个和那个。

顺便说一句,内核执行抢占式调度,因此上下文切换可能随时发生(通常每秒数百次)。当(在上下文切换时)在同一个内核上调度另一个进程时,需要重新配置 MMU(因为每个进程都有自己的虚拟地址空间,并且缓存再次“冷”了)。

您可能对处理器亲和性感兴趣。请参阅sched_setaffinity(2) 。阅读有关实时 Linux 的信息。请参阅sched(7)。并参阅numa(7)。

我完全不确定您所担心的性能影响是否明显(并且我相信在用户空间中这是无法避免的)。

也许您可以考虑将敏感代码移到内核空间(因此具有 CPL0 权限),但这可能需要数月的工作,而且可能不值得付出努力。我甚至不会尝试。

您是否考虑过使用其他完全不同的方法(例如,在您的 GPGPU 中使用 OpenCL 重写它)来处理对延迟敏感的代码?

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用