【问题标题】:Eliding cache snooping for thread-local memory消除线程本地内存的缓存侦听
【发布时间】:2021-03-24 01:31:35
【问题描述】:

现代多核 CPU 通过窥探在内核之间同步缓存,即每个内核广播它在内存访问方面所做的事情,并监视其他内核生成的广播,以确保内核 B 看到来自内核 A 的写入.

这很好,因为如果您确实需要在线程之间共享数据,它可以最大限度地减少您必须编写的代码量以确保它确实被共享。

糟糕的是,如果您的数据应该只存在于一个线程的本地,那么窥探仍然会发生,不断地消耗能量而没有任何目的。

如果您声明相关变量thread_local,是否仍会发生窥探?不幸的是,根据Can other threads modify thread-local memory?的接受答案,答案是肯定的

当前存在的任何平台(CPU 和操作系统的组合)是否提供任何方法来关闭线程本地数据的窥探?不必是便携的方式;如果它需要发出特定于操作系统的 API 调用,甚至需要放入程序集中,我仍然感兴趣。

【问题讨论】:

  • 现代多核 CPU 通过窥探在内核之间同步缓存 - 并非如此,这无法扩展功率和聚合 L3 缓存带宽。在实践中,现代 CPU 使用基于目录的一致性,例如英特尔的包容性 L3 缓存中的标签增加了位,以说明哪个内核可能具有修改后的行副本。
  • 不幸的是,这是为“透明”共享内存支持付费的众多方式之一。完全消除线程私有内存的窥探流量(或相应的目录查找)可能需要操作系统将线程“固定”到特定的缓存上下文,并且操作系统的架构使其永远不会接收到线程私有内存的指针,或者任何使用此类指针的系统调用必须在进行调用的同一内核上。分层(基于页面)目录可以减少大量的窥探流量,也许与扩展的 TLB 支持相结合。

标签: multithreading operating-system cpu-architecture cpu-cache thread-local


【解决方案1】:

大多数现代处理器使用目录一致性协议来保持同一 NUMA 节点中所有内核之间的一致性,并使用另一个目录一致性协议来保持所有 NUMA 节点和位于同一一致性域中的 IO 集线器之间的一致性,其中每个 NUMA 节点可以是活动套接字、活动套接字的一部分或节点控制器。关于真实处理器中的一致性的简要介绍可以在:Cache coherency(MESI protocol) between different levels of cache namely L1, L2 and L3 找到。

目录一致性协议显着减少了广播窥探的需求,因为它们为每个缓存行提供了额外的一致性状态,以基本上跟踪谁可能拥有该行的副本。在以下情况下仍可能发生不必要的窥探:

  • 在不通知目录控制器的情况下,一条线路会从核心或 NUMA 节点静默地逐出。
  • 目录状态可能受到错误检测代码的保护。如果认为状态已损坏,则需要广播。
  • 根据微架构,内存目录可能无法跟踪每个 NUMA 节点的缓存行,而是以“任何其他 NUMA 节点”为粒度。

不必要的窥探的成本不仅是额外的能源消耗,而且还有延迟,因为除非所有一致性事务都已完成,否则不能将请求视为非推测完成。这会显着增加完成请求的时间,进而限制带宽,因为每个未完成的请求都会消耗某些硬件资源。

只要真正用作线程局部变量并且拥有这些变量的线程很少在物理内核之间迁移,您就不必担心不必要的窥探来缓存存储线程局部变量的行。

【讨论】:

  • Snoop 过滤器还可以减少一致性流量。窥探的延迟成本也可能与读取内存的延迟重叠。带宽成本也是一个因素。一个完整的目录可以通过复制标签来实现,这很昂贵,或者为每个内存块存储目录数据(这需要与内存容量成比例的存储——用于 Alpha 21364 的一种技术是使用每个缓存块 ECC 并使用额外的位来持有有限的目录信息)。避免不必要的连贯活动仍然是一个理想的功能。
【解决方案2】:

有一个基本的基于失效的协议,MESI,它有点基础。它还有其他扩展,但它可以最大限度地减少读取或写入时的总线事务数。 MESI 对缓存行可以处于的状态进行编码:Modified、Exclusive、Shared、Invalid。 MESI 的基本示意图涉及两个视图。破折号(-)表示可能是内部状态更改,但不需要外部操作。从 CPU 到它的缓存:

           M   E  S   I
Read       -   -  -   2
Write      -   -  1   3

地点:

  1. 发出总线无效,将状态更改为 M。
  2. 发出总线读取,将状态更改为 S。
  3. 发出总线读取 + 总线无效,将状态更改为 M。

此外,这些状态“监听”外部总线,因此从总线到缓存:

           M   E  S  I
Read       4   -  -  -
Write      5   -  -  -
  1. 从缓存中刷新,更改为 S。
  2. 从缓存中刷新,更改为 I。

因此,总线代理合作以仅生成最少的必要事务。

许多 CPU,尤其是嵌入式控制器,都有 cpu-private-memory,这可能是线程本地存储的理想选择;但是,要将线程从一个内核迁移到另一个内核,则需要追踪其所有线程本地存储变量,并将它们(以某种方式)复制到新内核的私有内存中。

根据工作负载,这可能是可行的,但对于一般工作负载,最小化总线流量和放松亲和力是一个胜利。

【讨论】:

  • 这是 MESI 通常用来描述的共享总线模型,但现代真正的 CPU 不以这种方式工作。互连不是所有内核竞争访问的共享总线。例如英特尔 Sandybridge 系列使用环形总线 (realworldtech.com/sandy-bridge/8),或者在 Skylake-X 以后的服务器版本中使用网格。因此,所有内核都可以同时将消息传送到 L3 缓存片。他们使用基于目录的一致性。在 L3 未命中时一些额外的一致性开销,尤其是在多套接字系统上,以确保其他套接字没有对其进行修改。
猜你喜欢
  • 2020-01-18
  • 2011-11-16
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 2011-02-10
  • 2013-12-20
  • 2016-05-17
相关资源
最近更新 更多