【问题标题】:Force a migration of a cache line to another core强制将缓存行迁移到另一个内核
【发布时间】:2019-12-11 15:41:25
【问题描述】:

在用于 x86 硬件(例如 Intel Skylake)的 C++(使用平台上可用的任何低级内在函数)中,是否可以将缓存线发送到另一个内核而不强制该内核上的线程加载该线明确的?

我的用例在并发数据结构中。在这种情况下,在某些情况下,一个核心在探测点时会经过内存中可能由其他一些核心拥有的某些地方。这些内核上的线程通常在条件变量上被阻塞,因此它们有一些空闲周期可以运行额外的“有用工作”。这里“有用的工作”的一个例子可能是它们将数据流式传输到另一个内核,该内核将在将来加载它们,因此加载内核不必等待该行在处理它之前进入它的缓存。 x86 硬件上是否有一些内在/指令可用?


__builtin_prefetch 并没有很好地工作,因为由于某种原因,它最终将延迟添加到执行加载的代码中:(也许步幅没有很好地配置,但我无法获得好的步幅到目前为止。这可能会得到更好的处理,并且确定性地从知道他们的线路的其他核心最终可能会被加载。

【问题讨论】:

  • 有趣的想法,虽然当你深入细节时,它似乎非常复杂。您将如何识别和编码目标核心?你如何防止操作系统从中交换线程?如何防止缓存 DDoS 攻击。好像应该由SW层(OS/VMM)管理
  • @Leeor 我没有提供足够的关于用例的上下文,但我认为这种优化将是短暂的(例如,从有人推另一端的队列中弹出),任何某种调度不会对系统造成足够的影响而导致病态。 DDoS 缓存攻击是什么意思?
  • 用户级软件仍然需要知道操作系统决定在该阶段运行每个线程的位置。您可以通过亲和力来控制它,但这会产生其他责任。攻击的事情可能有点夸张,但是想想一个用户在云系统上购买一个核心只是为了让另一个用户不断地向他强行一些缓存行。
  • @Leeor 有道理。在这种情况下,代码可以从 sched_getcpu() 或 numa_node_of_cpu() 轮询核心配置。虽然这只是一种启发式方法。

标签: c++ assembly concurrency x86 cpu-cache


【解决方案1】:

没有“推”;只有在核心请求它之后,高速缓存行才会进入物理核心上的 L1d。 (因为加载、软件预取,甚至是硬件预取。)

2 个逻辑内核可以共享同一个物理内核,以防万一:如果某些未来负载的延迟远比吞吐量更重要,那么唤醒预取辅助线程来准备情况可能不会那么可怕。我正在想象让编写器使用条件变量或发送 POSIX 信号,或写入管道,或者会导致操作系统辅助唤醒另一个线程的东西,该线程的 CPU 亲和性设置为一个或两个逻辑核心您关心的其他一些线程也已固定到。


您可以从编写器方面做的最好的事情是触发回写到共享 (L3) 缓存,这样其他核心就可以在 L3 中命中,而不是发现它由其他核心拥有并拥有也等待回写。 (或者取决于uarch,用于直接核心->核心转移)

例如在 Ice Lake 或更高版本上,使用 clwb 强制回写,使其干净但仍被缓存。 (但请注意,这会迫使它一直运行到 DRAM。)clwb on SKX does evict like clflushopt

另请参阅CPU cache inhibition,我建议可能使用设置为直写缓存的内存区域,如果这在主流操作系统下是可能的。另见How to force cpu core to flush store buffer in c?

或者当然是将写入器和读取器固定到同一个物理内核,以便它们通过 L1d 进行通信。但随后它们会争夺执行资源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-16
    • 2014-10-01
    • 2017-12-14
    • 2018-06-01
    • 1970-01-01
    • 2013-07-02
    • 2016-02-10
    • 1970-01-01
    相关资源
    最近更新 更多