屏障/栅栏以及获取、释放语义是如何在微架构上实现的?

2024-03-17

很多问题以及文章/书籍,例如https://mirrors.edge.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2018.12.08a.pdf https://mirrors.edge.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2018.12.08a.pdf、Preshing 的文章如https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/ https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/以及他的整个系列文章,根据不同屏障类型提供的排序和可见性保证,抽象地讨论了内存排序。我的问题是这些屏障和内存排序语义是如何在 x86 和 ARM 微架构上实现的?

对于存储-存储屏障,似乎在 x86 上,存储缓冲区维护存储的程序顺序并将它们提交给 L1D(从而使它们以相同的顺序全局可见)。如果存储缓冲区没有排序,即不按程序顺序维护它们,那么如何实现存储存储屏障?它只是“标记”存储缓冲区,以便在屏障提交之前存储到缓存一致域之前存储之后?或者内存屏障是否实际上刷新存储缓冲区并停止所有指令直到刷新完成?可以双向实施吗?

对于负载-负载屏障,如何防止负载-负载重新排序?很难相信 x86 会按顺序执行所有加载!我假设加载可以无序执行,但可以按顺序提交/退出。如果是这样,如果一个 cpu 对 2 个不同的位置执行 2 次加载,那么一次加载如何确保它从 T100 获取值,而下一个加载在 T100 上或之后获取该值?如果第一次加载在缓存中未命中并正在等待数据,而第二次加载命中并获取其值,该怎么办?当加载 1 获取其值时,它如何确保它获取的值不是来自加载 2 的值的较新存储?如果加载可能无序执行,如何检测内存顺序的违规行为?

同样,如何实现加载-存储屏障(隐含在 x86 的所有加载中)以及如何实现存储-加载屏障(例如 mfence)?即 dmb ld/st 和 just dmb 指令在 ARM 上的微架构上做什么,每次加载和每次存储以及 mfence 指令在 x86 上的微架构上做什么以确保内存排序?


其中大部分已在其他问答中涵盖(尤其是后来的问答)C++ 如何仅使用 MOV 在 x86 上实现释放和获取? https://stackoverflow.com/questions/60314179/c-how-is-release-and-acquire-achieved-on-x86-only-using-mov),但我会在这里做一个总结。不过,这是个好问题,将所有这些收集到一个地方还是很有用的。


在 x86 上,每个 asm 加载都是获取加载。为了有效地实现这一点,现代 x86 硬件会推测性地早于允许的时间加载,然后检查该推测。 (可能会导致内存顺序错误推测管道核问题。)为了跟踪这一点,英特尔将加载和存储缓冲区的组合称为“内存顺序缓冲区”。

弱顺序 ISA 不必推测,它们可以按任何顺序加载。


x86 商店订购通过仅让存储按程序顺序从存储缓冲区提交到 L1d 来维护。

至少在 Intel CPU 上,存储缓冲区条目是已分配对于商店来说,发行时(从前端进入ROB + RS)。所有微指令都需要为其分配一个 ROB 条目,但某些微指令还需要分配其他资源,例如加载或存储缓冲区条目、它们读/写的寄存器的 RAT 条目等。

所以我认为存储缓冲区本身is ordered。当存储地址或存储数据微指令执行时,它仅将地址或数据写入其已分配的存储缓冲区条目。由于提交(释放 SB 条目)和分配都是按程序顺序进行的,因此我假设它实际上是一个具有头部和尾部的循环缓冲区,就像 ROB 一样。 (与 RS 不同)。


避免 LoadStore 基本上是免费的:加载在执行之前无法退出(从缓存中获取数据)。商店无法承诺,直到after它退休了。按顺序自动退出意味着所有先前的加载都在存储“毕业”并准备好提交之前完成。

在实践中,可以进行加载存储重新排序的弱有序 uarch 可能会记分板加载并在 ROB 中跟踪它们:一旦知道它们没有故障,就让它们退出,即使数据尚未到达。

这似乎更有可能出现在有序核心上,但我不知道。因此,您可能有一个已退役的负载,但如果在数据实际到达之前有任何东西试图读取它,则寄存器目标仍然会停止。我们知道,有序核心实际上以这种方式工作,不需要负载complete在后面的指令可以执行之前。 (这就是为什么使用大量寄存器的软件流水线在此类内核上如此有价值,例如实现 memcpy。立即在有序内核上读取加载结果会破坏内存并行性。)

如何通过按顺序提交实现加载->存储重新排序? https://stackoverflow.com/questions/52215031/how-is-load-store-reordering-possible-with-in-order-commit更深入地讨论有序与无序。


屏障指示

唯一对普通商店有作用的屏障指令是mfence实际上,这会停止内存操作(或整个管道),直到存储缓冲区耗尽。加载和存储是唯一需要重新排序的指令吗? https://stackoverflow.com/questions/50494658/are-loads-and-stores-the-only-instructions-that-gets-reordered涵盖了 Skylake-with-updated-microcode 的行为,就像lfence以及。

lfence主要存在的微架构效应是阻止后续指令的发出,直到所有先前的指令都离开无序后端(退休)。用例lfence内存排序几乎不存在。

Related:

  • C++ 如何仅使用 MOV 在 x86 上实现释放和获取? https://stackoverflow.com/questions/60314179/c-how-is-release-and-acquire-achieved-on-x86-only-using-mov
  • 内存屏障的传递性/累积性属性是如何在微架构上实现的? https://stackoverflow.com/questions/58018486/how-is-the-transitivity-cumulativity-property-of-memory-barriers-implemented-mic
  • x86 CPU 有多少条内存屏障指令? https://stackoverflow.com/questions/50323347/how-many-memory-barriers-instructions-does-an-x86-cpu-have
  • 如何体验“LFENCE或SFENCE无法通过较早的读/写” https://stackoverflow.com/questions/56705436/how-can-i-experience-lfence-or-sfence-can-not-pass-earlier-read-write
  • lock xchg 与 mfence 具有相同的行为吗? https://stackoverflow.com/questions/40409297/does-lock-xchg-have-the-same-behavior-as-mfence
  • 英特尔内存模型是否使 SFENCE 和 LFENCE 变得冗余? https://stackoverflow.com/questions/32705169/does-the-intel-memory-model-make-sfence-and-lfence-redundant
  • 了解 lfence 对具有两个长依赖链的循环的影响,以增加长度 https://stackoverflow.com/questions/51986046/understanding-the-impact-of-lfence-on-a-loop-with-two-long-dependency-chains-fo详细介绍了 LFENCE 如何停止执行后续指令,以及这对性能意味着什么。
  • 我什么时候应该使用 _mm_sfence _mm_lfence 和 _mm_mfence https://stackoverflow.com/questions/4537753/when-should-i-use-mm-sfence-mm-lfence-and-mm-mfence/50780314#50780314高级语言的内存模型比 x86 弱,因此有时只需要一个不编译为 asm 指令的屏障。使用_mm_sfence()当你没有使用任何 NT 存储时,只会让你的代码无缘无故地变慢atomic_thread_fence(mo_release).
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

屏障/栅栏以及获取、释放语义是如何在微架构上实现的? 的相关文章

  • x86-64 Linux 中不再允许使用 32 位绝对地址?

    64 位 Linux 默认使用小内存模型 将所有代码和静态数据置于 2GB 地址限制以下 这确保您可以使用 32 位绝对地址 旧版本的 gcc 对静态数组使用 32 位绝对地址 以便节省相对地址计算的额外指令 然而 这不再有效 如果我尝试在
  • 如何在 Ubuntu 14.04 LTS 中安装 ia32-libs (Trusty Tahr)

    我昨天安装了 Ubuntu 14 04 Trusty Tahr 一切看起来都还好 但是当我尝试编译一些C代码时 我遇到了以下错误 该错误似乎是由于操作系统缺乏 32 位架构支持造成的 错误输出如下 usr bin ld i386 archi
  • 为什么当设置为 TLS 选择器时,ES 和 DS 在 64 位内核上最终会归零?

    下面的 32 位程序调用set thread area 2 http linux die net man 2 set thread area在 GDT 中创建一个条目 该条目旨在用于 TLS 通常将结果选择器放入FS or GS并成功使用
  • x86 平台中的 KVM 影子页表处理

    据我了解 在没有硬件支持来宾虚拟到主机物理地址转换的处理器上 KVM 使用影子页表 当来宾操作系统修改其页表时 会构建和更新影子页表 硬件中有没有专门的指令 以x86为参考 来修改页表 除非有特殊说明 否则不会对VMM 造成陷阱 Linux
  • 一条指令可以同时处于两种寻址模式吗?

    我在书中读到了以下内容从头开始编程 处理器有多种不同的访问数据的方式 称为 寻址模式 最简单的模式是立即模式 其中 要访问的数据嵌入在指令本身中 例如 如果我们想将寄存器初始化为 0 而不是给出 计算机要从中读取 0 的地址 我们将指定立即
  • C++ 中的 CPUID 实现

    我想知道这里是否有人有一些可以从任何托管 net 语言引用的 C CPUID 实现的好示例 另外 如果情况并非如此 我是否应该注意 X86 和 X64 之间的某些实现差异 我想使用 CPUID 来获取运行我的软件的机器上的信息 崩溃报告等
  • 为 Visual Studio 应用程序设置平台目标的目的是什么?

    对于任何 VS 项目 都可以在该项目的构建属性中设置平台目标 您可以将其设置为任何 CPU x86 x64 或 Itanium 我的问题是 如果我将此值设置为 x86 是否意味着我无法在 x64 计算机上运行该项目 如果是这样 为什么还要使
  • 如何在汇编语言中换行打印多个字符串

    我试图在汇编中的不同行上打印多个字符串 但使用我的代码 它只打印最后一个字符串 我对汇编语言非常陌生 所以请耐心等待 section text global start start mov edx len mov edx len1 mov
  • 在 x86 Intel VT-X 非根模式下,是否可以在每个指令边界传递中断?

    除了不将中断传送到虚拟处理器的某些正常指定条件 cli if 0 等 之外 客户机中的所有指令实际上都是可中断的吗 也就是说 当传入的硬件中断先传递给 LAPIC 然后传递给处理器时 据说会发生一些内部魔法 将其转换为虚拟中断给来宾 使用虚
  • g++.exe 和 x86_64-w64-mingw32-g++.exe 有什么区别?

    同样的问题也适用于 gcc ar 等 在 Code Blocks 中将工具链可执行文件从 Something exe 更改为 x86 64 w64 mingw32 something exe 时 代码仍然可以完美编译 此外 32 位和 64
  • 奇怪的 MSC 8.0 错误:“ESP 的值未在函数调用中正确保存...”

    我们最近尝试将一些 Visual Studio 项目分解为库 并且在测试项目中一切似乎都编译和构建得很好 其中一个库项目作为依赖项 然而 尝试运行该应用程序给我们带来了以下令人讨厌的运行时错误消息 运行时检查失败 0 ESP 的值未在函数调
  • Verilog 双向握手示例

    我正在完成一个项目 要求是处理器内部功能单元之间的双向握手 我知道它是什么 但是有没有任何 标准 或一个简单的例子 我唯一能想到的就是两个单元之间 当它们之间有一条数据线并且当 X 发送到 Y 时 会给出一个单独的 发送 信号 当 Y 接收
  • Intel 64 和 IA-32 上的 MESI 有何意义

    MESI 的要点是保留共享内存系统的概念 然而 对于存储缓冲区 事情就变得复杂了 一旦数据到达 MESI 实现的缓存 下游内存就会保持一致 然而 在此之前 每个核心可能对内存位置 X 中的内容存在分歧 具体取决于每个核心的本地存储缓冲区中的
  • 从 NASM 调用 C 函数 _printf 会导致分段错误

    我一直在尝试使用 NASM 在 Mac OS 和 Windows 上学习 64 位汇编 我的代码是 extern printf section data msg db Hello World 10 0 section text global
  • 程序集比较标志理解

    我正在努力理解汇编程序中的以下代码片段 if EAX gt 5 EBX 1 else EBX 2 在汇编程序中 可以写如下 根据我的书 模拟jge操作说明 https www felixcloutier com x86 jcc您通常会使用
  • Linux内核页表更新

    在linux x86 中分页 每个进程都有它自己的页面目录 页表遍历从 CR3 指向的页目录开始 每个进程共享内核页目录内容 假设三个句子是正确的 假设某个进程进入内核 模式并更新他的内核页目录内容 地址映射 访问 权利等 问题 由于内核地
  • 如何在 icarus verilog 中包含文件?

    我知道基本的 include filename v 命令 但是 我试图包含另一个文件夹中的模块 现在 该模块还包括同一文件夹中存在的其他模块 但是 当我尝试在最顶层运行该模块时 出现错误 C Users Dell Desktop MIPS
  • AVX-512 指令编码 - {er} 含义

    在 Intel x86 指令集参考中 有许多 AVX 512 指令在指令中具有可选的 er 例如 VADDPD 的一种形式定义为 EVEX NDS 512 66 0F W1 58 r VADDPD zmm1 k1 z zmm2 zmm3 m
  • 按字节数对向量进行混洗

    有什么办法可以左移 v 0 gt v 1 a m128i by n字节 其中n仅在运行时才知道 我目前仅限于 AVX1 但如果 AVX2 512 使这变得更容易 我非常感兴趣 I found mm bslli si128 m128i imm
  • 是否可以在VM内使用VMX CPU指令?

    VM guest 内部的进程是否有可能使用 VMX AMD V VT x CPU 指令 然后由外部 VMM 处理而不是直接在 CPU 上处理 Edit 假设外部VM使用VMX本身来管理其虚拟客户机 即它在Ring 1中运行 如果可能的话 是

随机推荐

  • Erlang 记忆的简单示例

    假设您有一个简单的函数 对于较大的值来说 它的成本可能会相当高 fact 0 gt 1 fact N gt N fact N 1 在哪里可以找到使用缓存 或记忆 函数值的简单示例dets 任何其他方便记忆的方法都将受到高度赞赏 根据您的情况
  • symfony2 表单复选框分组(扩展和多项选择)

    在我的表单类型中我有这个 builder gt add options choice choices gt choices multiple gt true expanded gt true label gt false 选择是一个数组 c
  • 为什么SQL不支持“= null”而不支持“is null”?

    我不是在问if确实如此 我知道事实并非如此 我很好奇原因 我已阅读过诸如此之类的支持文档关于在 MySQL 中使用 Null 值 http dev mysql com doc refman 5 0 en working with null
  • Eclipse 打开空白工作区

    我什至不知道在哪里寻找这个问题 发生的情况是 当我打开 Eclipse 时 它 会打开一个空白工作区 然后我必须切换到当前的 现在每次打开 Eclipse 都会发生这种情况 知道我应该在哪里解决这个问题吗 日食朱诺 看看 eclipse安装
  • 为转译而构建的抽象(编程)语言

    介绍 我经常遇到这样的情况 库是用特定的编程语言编写的 这很好 如果我想以同一种语言使用该库 但如果我想使用不同的语言 这将是一个问题 这并不意味着可能存在或多或少的 hacky 方式 对于某些库 我感觉它们是用特定的编程语言编写的 只是因
  • 如何使用 markdown 按顺序编写两个单独的块引用?

    我需要按顺序放置两个块引用 但是 markdown 将它们组合成一个块引用 我能让它们分开的唯一方法是在它们之间放置一些垃圾文本 由于此文本字段允许我使用 Markdown 因此我可以演示 gt First Quote gt Second
  • 如何从 Emacs 中的混乱情况中恢复?

    我刚刚开始使用 Emacs 有时我会尝试一些东西 当我完成实验时 我想返回到我正在编辑的缓冲区 但我不知道如何做 更糟糕的是 有时我不小心敲到了一个键 甚至不知道我敲到了什么 在 Vim 中 我只需按 ESC 即可恢复 Emacs中有没有类
  • 指定 Random.nextInt() 的最大值和最小值? [复制]

    这个问题在这里已经有答案了 可能的重复 Java 生成一定范围内的随机数 https stackoverflow com questions 363681 java generating random number in a range 我
  • 从 Jest 到 stdout 再到 GitLab 的代码覆盖率

    我正在 GitLab CI 中运行代码覆盖率的玩笑测试 GitLab 从 gitlab 中运行程序的标准输出捕获百分比 jest coverage在 stdout 中生成覆盖范围 并且 gitlab 使用以下命令捕获它 All files
  • 从javascript中的字符串中提取带有“=”的变量的最佳方法是什么

    我想从这样的字符串中提取变量名称 foo valor bar second 等等 回来 foo valor bar second 您可以使用正则表达式展望 https www regular expressions info lookaro
  • Cassandra 时间序列数据模型

    我正在研究用于存储时间序列的 Cassandra 数据模型 我是 Cassandra 新手 我有两个应用程序 日内股票数据和传感器数据 股票数据将以一分钟的时间分辨率保存 七个数据字段构建一个时间范围 符号 日期时间 开盘价 最高价 最低价
  • 如何测试两个时间范围是否重叠?

    我需要实现预订功能并确保预订不会在 Rails 应用程序中重叠 The cover and between 方法不太符合我的需要 与同一模型上的其他潜在范围相比 我必须确保时间范围的唯一性 并高效地做到这一点 我认为可以使用overlaps
  • Python:Ascii字符<->十进制表示转换

    您好 我需要能够将 ascii 字符转换为其十进制等效字符 反之亦然 我怎样才能做到这一点 num ord char char chr num 例如 gt gt gt ord a 97 gt gt gt chr 98 b 您可以阅读有关 P
  • 添加不存在的订单元数据以扩展 WooCommerce 管理订单对特定产品的搜索

    继我之前的问题之后 我还有一个问题 添加不存在的订单元数据以扩展 WooCommerce 管理订单搜索 https stackoverflow com questions 77206771 add unexisting order meta
  • 读已提交隔离级别是否会导致死锁(Sql Server)?

    我的理解deadlocks是 两个进程试图争夺同一资源 通常是两个进程试图 写入 同一行数据 如果一个进程所做的只是读取数据 而另一个进程正在更新数据 那么这怎么会是资源争用呢 然而 在我们的数据库中 它被设置为默认事务级别ReadComm
  • 如何禁止取消选择 ListView 中的项目?

    I ve got
  • 如何在不进行字符串转换的情况下计算整数中的数字?

    我担心这个问题有一个简单而明显的答案 我需要确定物品计数的位数 以便我可以用minimum保持对齐所需的前导零的数量 例如 如果总数 一种解决方案是将项目计数转换为字符串 然后计算字符数 哎呀 有没有更好的办法 编辑 我不会想到使用常用对数
  • 执行“docker Push”时 gcloud ping 尝试失败

    我运行了以下命令 gcloud preview docker push gcr io project name an image 我收到以下错误 有谁知道我如何解决这个问题或者这意味着什么 我所做的只是遵循标准示例只是为了了解它是如何工作的
  • Android MediaPlayer 卡在prepare() 中

    我遇到了一个严重的问题 媒体播放器 MP 卡在prepare 方法 我的应用程序运行prepare in an AsyncTask以避免阻塞 UI 因为来源来自网络 有几个 播放 按钮用户可以随时单击 因此我添加了prepare 在同步方法
  • 屏障/栅栏以及获取、释放语义是如何在微架构上实现的?

    很多问题以及文章 书籍 例如https mirrors edge kernel org pub linux kernel people paulmck perfbook perfbook 2018 12 08a pdf https mirr