AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 76971964
Accepted
ajp
ajp
Asked: 2023-08-25 02:12:24 +0800 CST2023-08-25 02:12:24 +0800 CST 2023-08-25 02:12:24 +0800 CST

从缓存中刷新低争用原子的最佳方式?

  • 772

如果我有一些原子变量

  • 访问相对较少(低争用)
  • 由线程/核心统一随机访问(即,如果线程 A 写入变量,则很可能不是A下一个访问该变量)

那么,当 A 完成对变量的写入时,我是否应该以某种方式显式地将变量从线程 A 核心的 l1/l2/l3 缓存中刷新出来,以便当其他线程 B 需要访问该变量时后来,它在 RAM 中找到一个干净的缓存行,而不是另一个核心拥有的脏缓存行?

一些子问题

  • 从 RAM 访问干净的缓存行比从另一个核心访问脏的缓存行更快还是更慢?我假设前者在这里更快,但也许不是?
  • 而不是一直到 RAM,刷新到共享 l3 缓存(并且从每个核心的 l1/l2 中)是否足够?
  • 如果将缓存行刷新/写入 RAM(或 l3)是有益的,我该怎么做?

另外,我应该阅读哪些涵盖此类信息的文档/等?

multithreading
  • 1 1 个回答
  • 20 Views

1 个回答

  • Voted
  1. Best Answer
    Peter Cordes
    2023-08-25T04:14:38+08:002023-08-25T04:14:38+08:00

    TL:DR:在 x86 上你想要cldemote. 其他事情可能不值得做,特别是如果您的编写器线程可以在此商店之后做有用的工作。或者,如果没有,并且操作系统没有其他线程在该核心上运行,则将核心置于深度睡眠状态将涉及 CPU 在关闭其专用缓存之前写回其脏缓存行。


    我预计读取 RAM 通常比另一个内核中的脏线慢,尤其是在单插槽系统中。 (在多插槽 NUMA 系统中,如果远程核心具有由本地 DRAM 支持的缓存行的脏副本,则可能会改变情况,或者至少使 DRAM 不那么落后。)

    如果不存在好的(对作者来说便宜的)回写指令,那么什么也不做可能比走得太远更好。

    DRAM 延迟首先必须在 L3 中丢失,然后来自该 L3 切片的消息必须通过互连(例如环形总线或网格)到达内存控制器,然后您必须等待外部内存总线上的 DRAM 命令延迟。并且内存控制器中可能已经有一些排队的请求,您的内存控制器在后面等待。然后数据必须返回到执行加载的核心。

    另一个核心中的脏线在检测到 L3 未命中后还会涉及另一条消息,但会发送到拥有该线的核心。(L3 标签本身可能表明这一点,就像在 Intel CPU 上一样,出于这个原因,它使用包容性 L3。否则,一个单独的目录充当窥探过滤器)。它应该能够比 DRAM 控制器更快地响应,因为它只需从快速 L2 或 L1d 缓存中读取数据并将其发送到 L3 切片。(而且还直接到达想要它的核心?)


    理想的情况是最后一级(通常是 L3)缓存命中,以支持一致性流量。 因此,您希望从最后一个核心的私有 L1d/L2 缓存中逐出该行来写入它。(或者至少写回 L3 并在这些私有缓存中降级为共享状态,而不是独占/修改。因此,从同一核心的读取可能会在 L1d 中命中,只需要离核流量(并且 RFO = 读取所有权),如果它又写了。)

    但并非所有 ISA 都有指令可以廉价地执行此操作(不会使写入器减慢太多)或不会走得太远并强制写入 RAM。 像 x86 这样的指令clwb强制写入 RAM,但之后在 L3 中保持线路干净,在某些用例中可能值得考虑,但会浪费 DRAM 带宽。(但请注意,Skylake 实现clwb为clflushopt;仅在 Ice Lake 中以及后来的版本中,它实际上保留数据缓存以及写回 DRAM)。

    如果不经常访问它,有时它会在任何其他核心读取或写入它之前,仅从最后一个要写入的核心上的普通活动(例如循环数组)写回 L3。这太好了,任何从 L3 强制驱逐的行为都可以防止这种情况发生。如果该行的访问频率足以在 L3 缓存中正常保持热状态,那么您就不想破坏它。

    如果写入器线程/核心在写入后没有任何其他事情可做,您可以想象访问其他缓存行以尝试通过正常的伪 LRU 机制驱逐重要的写入,但这只有在负载下一个读取器的延迟非常重要,以至于值得在写入线程中浪费大量 CPU 时间并为其他缓存行生成额外的一致性流量,以便在其他线程中针对稍后的时间进行优化。


    有关的:

    • 有没有办法编写Intel CPU直接核对核通信代码?- CPU 对于在一个核心上写入、在另一个核心上读取进行了很好的优化,因为这是实际代码中的常见模式。

    • 除了提供必要的保证之外,硬件内存屏障是否还能使原子操作的可见性更快?(即,当该核心提交到 L1d 时,或者当它使其他缓存无效时,它们必须向此请求:不,它不会直接使速度更快,并且不值得这样做。)

    • x86 MESI 无效缓存行延迟问题- 建议让第三个线程每毫秒读取共享数据,以从最后一个写入器中提取数据,从而使高优先级线程最终读取数据的效率更高。

    • CPU 缓存抑制(相当以 x86 为中心)


    各种 ISA 的说明

    • 用于将脏缓存行写入下一级缓存的 RISC-V 指令- RISC-V 不存在这样的指令,至少在 2020 年不存在。

    • ARM/AArch64:我不知道,但如果有的话我不会感到惊讶。欢迎编辑。

    • 还有其他 ISA 具有有趣的缓存管理指令吗?

    x86 - 直到最近才发现什么好东西cldemote

    • NT 存储:绕过高速缓存一直到 L3,并强制逐出该行(如果以前不是)。所以这是一场灾难。

    • clflush/ clflushopt- 这些会一直驱逐到 DRAM,您不希望这样。(与缓存预取提示相反的是刷新小数组的一些性能数据。)

    • clwb- 此操作会一直写回 DRAM,但会将数据缓存在 Ice Lake 及更高版本上。(在 Skylake/Cascade Lake 中,它实际上与 运行相同clflushopt。至少它运行时没有错误,因此未来的持久内存库可以直接使用它,而无需检查 ISA 版本内容。)并且对 DRAM 的提交(可能是 NV-DIMM)可以被排序sfence,所以大概核心必须一直跟踪它,占用队列中的空间?

    • cldemote在 Tremont 和 Sapphire Rapids 中 - 正是为这个用例而设计的:它是一个性能提示,就像预取的反面一样。它写回到L3。nop它在不支持它的 CPU 上运行,因为他们故意选择了现有 CPU 已经作为以前未记录的 NOP 运行的编码。

      向硬件提示,包含内存操作数指定的线性地址的高速缓存行应从最靠近处理器核心的高速缓存移动(“降级”)到距处理器核心更远的级别。这可以加速同一一致性域中的其他核对该行的后续访问,特别是如果该行是由降级该行的核写入的。以这种方式移动线路是一种性能优化,即,它是一种不修改架构状态的提示。硬件可以选择高速缓存层次结构中的哪个级别来保留该行(例如,典型服务器设计中的L3)。源操作数是字节内存位置。

    与 不同的是clwb,它没有保证的行为(只是提示),也没有排序。即使是栅栏指令,也仅是wrt。存储到同一缓存行。因此,在通过互连发送带有要写入 L3 的数据的消息后,核心不必跟踪请求(并通知该核心的线路副本不干净。)

    • 1

相关问题

  • Rust:遍历文件夹并打开每个文件

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    使用 <font color="#xxx"> 突出显示 html 中的代码

    • 2 个回答
  • Marko Smith

    为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类?

    • 1 个回答
  • Marko Smith

    您可以使用花括号初始化列表作为(默认)模板参数吗?

    • 2 个回答
  • Marko Smith

    为什么列表推导式在内部创建一个函数?

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 个回答
  • Marko Smith

    为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)?

    • 4 个回答
  • Marko Smith

    为什么库中不调用全局变量的构造函数?

    • 1 个回答
  • Marko Smith

    std::common_reference_with 在元组上的行为不一致。哪个是对的?

    • 1 个回答
  • Marko Smith

    C++17 中 std::byte 只能按位运算?

    • 1 个回答
  • Martin Hope
    fbrereto 为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 您可以使用花括号初始化列表作为(默认)模板参数吗? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi 为什么列表推导式在内部创建一个函数? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A fmt 格式 %H:%M:%S 不带小数 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python C++20 的 std::views::filter 未正确过滤视图 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute 为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa 为什么库中不调用全局变量的构造函数? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis std::common_reference_with 在元组上的行为不一致。哪个是对的? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev 为什么编译器在这里错过矢量化? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan C++17 中 std::byte 只能按位运算? 2023-08-17 17:13:58 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve