什么时候需要x86 LFENCE,SFENCE和MFENCE指令?

use*_*112 40 cpu x86 assembly multithreading memory-fences

好吧,我已经从SO关于x86处理器围栏阅读下列适量(LFENCE,SFENCEMFENCE):

和:

而且我必须说实话,我还不能确定何时需要围栏.我试图从删除完全锁定并尝试通过栅栏使用更细粒度的锁定的角度来理解,以最小化延迟延迟.

首先,这是我不明白的两个具体问题:

有时在进行存储时,CPU会写入其存储缓冲区而不是L1缓存.但是,我不了解CPU执行此操作的条款?

CPU2可能希望加载已写入CPU1的存储缓冲区的值.据我了解,问题是CPU2无法在CPU1的存储缓冲区中看到新值.为什么MESI协议不能将刷新存储缓冲区作为其协议的一部分?

更一般地,可以请人试图描述的总体方案,并帮助时解释LFENCE/ MFENCESFENCE被需要的指令?

NB阅读本主题的一个问题是,当我只对Intel x86-64架构感兴趣时,"通常"为多CPU架构编写的文章数量.

Ale*_*lex 39

最简单的答案是:你必须使用的3个围墙一(LFENCE,SFENCE,MFENCE),以提供6个数据一致性的一种:

  • 轻松
  • 消耗
  • 获得
  • 发布
  • 收购释
  • 顺序

C++ 11:

最初,您应该从内存访问顺序的角度考虑这个问题,这在C++ 11中有详细记录和标准化.您应该先阅读:http://en.cppreference.com/w/cpp/atomic/memory_order

86/x86_64的:

1.获取 - 释放一致性:然后,重要的是要理解在x86中访问传统RAM(默认标记为WB - 回写,与WT(写入)或UC(Uncacheable)相同的效果)使用asm MOV而不使用任何其他命令会自动为Acquire-Release Consistency提供内存顺序 - std::memory_order_acq_rel.即,对于这种记忆而言,std::memory_order_seq_cst仅用于提供顺序一致性是有意义的.即,当您使用时:std::memory_order_relaxed或者std::memory_order_acq_rel编译后的汇编代码std::atomic::store()(或std::atomic::load())将是相同的 - 只有MOV没有L/S/MFENCE.

注意:但是你必须知道,不仅CPU而且C++编译器可以对内存重新排序操作,并且所有6个内存屏障总是会影响C++编译器,无论CPU架构如何.

然后,您必须知道,如何从C++编译为ASM(本机机器代码)或如何在汇编程序上编写它.为了提供任何一致性排除顺序,你可以简单的写MOV,例如MOV reg, [addr]MOV [addr], reg 等.

2.顺序一致性:但是为了提供顺序一致性,您必须使用隐含(LOCK)或显式围栏(L/S/MFENCE),如下所述:为什么GCC不使用LOAD(没有fence)和STORE + SFENCE用于顺序一致性?

  1. LOAD(没有围栏)和STORE+MFENCE
  2. LOAD (没有围栏)和 LOCK XCHG
  3. MFENCE+ LOADSTORE(没有围栏)
  4. LOCK XADD(0)和STORE(没有围栏)

例如,GCC使用1,但MSVC使用2. (但你必须知道,MSVS2012有一个错误:`std :: memory_order_acquire`的语义是否需要x86/x86_64上的处理器指令?)

然后,您可以阅读Herb Sutter,您的链接:https://onedrive.live.com/view.aspx?status = 4E86B0CF20EF15AD!24884&app = WordPdf&authkey =!AMtj_EflYn2507c

规则的例外情况:

此规则适用于通过使用MOV默认标记为WB - Write Back的常规RAM 进行访问.存储器被标记在页表中,在每个PTE(页表Enrty)对于每一页(4 KB连续存储器).

但也有一些例外:

  1. 如果我们将Page Table中的内存标记为Write Combined(ioremap_wc()在POSIX中),则automaticaly只提供Acquire Consistency,我们必须按照以下段落进行操作.

  2. 请参阅我的问题的答案:https://stackoverflow.com/a/27302931/1558037

  • 写入内存不会与其他写入重新排序,但以下情况除外:
    • 使用CLFLUSH指令执行的写操作;
    • 使用非时间移动指令(MOVNTI,MOVNTQ,MOVNTDQ,MOVNTPS和MOVNTPD)执行的流存储(写入); 和
    • 字符串操作(参见第8.2.4.1节).

在情况1和2中,SFENCE即使您希望获取 - 释放一致性,也必须在两次写入同一地址之间使用额外的,因为此处自动提供仅获取一致性并且您必须SFENCE自己执行Release().

回答你的两个问题:

有时在进行存储时,CPU会写入其存储缓冲区而不是L1缓存.但是,我不了解CPU执行此操作的条款?

从用户的角度来看,高速缓存L1和存储缓冲器的行为不同.L1快,但Store-Buffer更快.

  • 存储缓冲区 - 是一个简单的队列,其中只存储写入,并且无法重新排序 - 它是为了提高性能和隐藏访问缓存的延迟(L1 - 1ns,L2 - 3ns,L3 - 10ns)(CPU核心)认为Write已经存储到缓存并执行下一个命令,但同时你的Writes只保存到Store-Buffer并将保存到缓存L1/2/3),即CPU-Core不需要等待Writes将被存储到缓存中.

  • 缓存L1/2/3 - 看起来像透明的关联数组(地址 - 值).这是快,但不是最快的,因为86使用自动提供,获取,释放一致性高速缓存一致性协议MESIF/MOESI.它用于更简单的多线程编程,但会降低性能.(实际上,我们可以使用Write Contentions Free算法和数据结构,而不使用缓存相干,即不使用MESIF/MOESI,例如通过PCI Express).协议MESIF/MOESI适用于QPI,它连接多处理器系统(ccNUMA)中不同CPU之间的CPU和内核中的内核.

CPU2可能希望加载已写入CPU1的存储缓冲区的值.据我了解,问题是CPU2无法在CPU1的存储缓冲区中看到新值.

是.

为什么MESI协议不能将刷新存储缓冲区作为其协议的一部分?

MESI协议不能只包括刷新存储缓冲区作为其协议的一部分,因为:

  • MESI/MOESI/MESIF protoclos与Store-Buffer无关,也不知道它.
  • 在每个Writes上自动刷新Store Buffer会降低性能 - 并且会使它无用.
  • 通过使用某些命令手动刷新所有远程CPU核心上的存储缓冲区(我们不知道哪个核心存储缓冲区包含所需的写入)会降低性能(在8个CPU中x 15个核心= 120个核心同时刷新存储-Buffer - 这很糟糕)

但是manualy在当前CPU-Core上刷新Store Buffer - 是的,你可以通过执行SFENCE命令来完成它.您可以SFENCE在两种情况下使用:

  • 在具有回写可缓存的RAM上提供顺序一致性
  • 提供规则例外的获取 - 释放一致性:具有写入组合可缓存的RAM,用于使用CLFLUSH指令执行的写入和用于非时间SSE/AVX命令的写入

注意:

LFENCE在任何情况下我们都需要x86/x86_64吗?- 问题并不总是很清楚:处理器x86/x86_64中的LFENCE是否有任何意义?

其他平台:

然后,您可以在理论上(对于真空中的球形处理器)使用Store-Buffer和Invalidate-Queue阅读您的链接:http://www.puppetmastertrading.com/images/hwViewForSwHackers.pdf

以及如何在其他平台上提供顺序一致性,不仅包括L/S/MFENCE和LOCK,还包括LL/SC:http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

  • 你真的应该把 `LFENCE` 和 `SFENCE` 与 `mfence` 分开讨论。使用 NT 存储时只需要 SFENCE。对于实际的内存排序,您几乎根本不需要 LFENCE,只是因为它的部分序列化效果,例如使用 `rdtsc`([为什么(或不是?)SFENCE + LFENCE 等价于 MFENCE?](https:// stackoverflow.com/q/27627969) 和 [我什么时候应该使用 \_mm\_sfence \_mm\_lfence 和 \_mm\_mfence](/sf/ask/317642741/))。`mfence` 是唯一对正常内存排序有用的屏障。`lfence` 和 `sfence` 对任何放松到 seq_cst 的人都没有用 (2认同)

归档时间:

查看次数:

17927 次

最近记录:

10 年,3 月 前