假设我们正在尝试使用tsc进行性能监控,我们希望防止指令重新排序.
这些是我们的选择:
1: rdtscp
是序列化调用.它可以防止对rdtscp的调用进行重新排序.
__asm__ __volatile__("rdtscp; " // serializing read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc variable
:
: "%rcx", "%rdx"); // rcx and rdx are clobbered
Run Code Online (Sandbox Code Playgroud)
但是,rdtscp
仅适用于较新的CPU.所以在这种情况下我们必须使用rdtsc
.但是rdtsc
非序列化,因此单独使用它不会阻止CPU重新排序.
所以我们可以使用这两个选项中的任何一个来防止重新排序:
2:这是一个电话cpuid
然后rdtsc
.cpuid
是一个序列化的电话.
volatile int dont_remove __attribute__((unused)); // volatile to stop optimizing
unsigned tmp;
__cpuid(0, tmp, tmp, tmp, …
Run Code Online (Sandbox Code Playgroud) 好吧,我已经从SO关于x86处理器围栏阅读下列适量(LFENCE
,SFENCE
和MFENCE
):
和:
而且我必须说实话,我还不能确定何时需要围栏.我试图从删除完全锁定并尝试通过栅栏使用更细粒度的锁定的角度来理解,以最小化延迟延迟.
首先,这是我不明白的两个具体问题:
有时在进行存储时,CPU会写入其存储缓冲区而不是L1缓存.但是,我不了解CPU执行此操作的条款?
CPU2可能希望加载已写入CPU1的存储缓冲区的值.据我了解,问题是CPU2无法在CPU1的存储缓冲区中看到新值.为什么MESI协议不能将刷新存储缓冲区作为其协议的一部分?
更一般地,可以请人试图描述的总体方案,并帮助时解释LFENCE
/ MFENCE
和SFENCE
被需要的指令?
NB阅读本主题的一个问题是,当我只对Intel x86-64架构感兴趣时,"通常"为多CPU架构编写的文章数量.
标准C++ 11是否保证memory_order_seq_cst
阻止StoreLoad重新排序原子操作以进行非原子内存访问?
众所周知,std::memory_order
C++ 11中有6 个,它指定了如何围绕原子操作对常规的非原子内存访问进行排序 - 工作草案,编程语言C++标准2016-07-12:http:/ /www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
§29.3顺序和一致性
§29.3/ 1
枚举memory_order指定1.10中定义的详细常规(非原子)内存同步顺序,并且可以提供操作排序.其枚举值及其含义如下:
众所周知,这6个memory_orders会阻止其中一些重新排序:
但是,是否会memory_order_seq_cst
阻止StoreLoad围绕原子操作重新排序以进行常规的非原子内存访问,或仅针对其他具有相同原子的原子进行重新排序memory_order_seq_cst
?
即,如果我们同时使用std::memory_order_seq_cst
STORE和LOAD,或仅用于其中一个,则阻止此StoreLoad重新排序?
std::atomic<int> a, b;
b.store(1, std::memory_order_seq_cst); // Sequential Consistency
a.load(std::memory_order_seq_cst); // Sequential Consistency
Run Code Online (Sandbox Code Playgroud)
关于Acquire-Release语义是明确的,它完全指定了跨原子操作的非原子内存访问重新排序:http://en.cppreference.com/w/cpp/atomic/memory_order
为防止StoreLoad重新排序,我们应该使用std::memory_order_seq_cst
.
两个例子:
std::memory_order_seq_cst
对于STORE和LOAD:有MFENCE
StoreLoad无法重新排序 - GCC 6.1.0 x86_64:https://godbolt.org/g/mVZJs0
std::atomic<int> a, b;
b.store(1, std::memory_order_seq_cst); // can't be executed after LOAD
a.load(std::memory_order_seq_cst); // …
Run Code Online (Sandbox Code Playgroud) 正如我们从C11-memory_order所知道的那样:http://en.cppreference.com/w/c/atomic/memory_order
从C++ 11-std :: memory_order开始:http://en.cppreference.com/w/cpp/atomic/memory_order
在强排序系统(x86,SPARC,IBM大型机)上, 发布 - 获取顺序是自动的.没有为此同步模式发出额外的CPU指令,只会影响某些编译器优化(例如,禁止编译器在原子存储释放之前移动非原子存储或在原子载荷获取之前执行非原子加载)
但这对于x86-SSE指令是否正确(除了[NT] - 非时间,我们总是必须使用L/S/MFENCE)?
这里说,"sse指令......不要求向后兼容性,并且内存顺序未定义".据信,当需要时,严格的可订购性与旧版本的处理器x86兼容,但是新的命令,即SSE(除了[NT]) - 被剥夺了自动释放 - 获取订单,是吗?
正如我们从之前的回答中所知道的,它是否在处理器x86/x86_64中指示LFENCE?我们不能使用SFENCE
而不是MFENCE
顺序一致性.
这里的答案表明MFENCE
= SFENCE
+ LFENCE
,即LFENCE
没有我们不能提供顺序一致性的东西.
LFENCE
无法重新排序:
SFENCE
LFENCE
MOV reg, [addr]
Run Code Online (Sandbox Code Playgroud)
- 到 - >
MOV reg, [addr]
SFENCE
LFENCE
Run Code Online (Sandbox Code Playgroud)
例如重新排序MOV [addr], reg
LFENCE
- > LFENCE
MOV [addr], reg
由机制提供- 存储缓冲区,它重新排序存储 - 负载以提高性能,并且因为LFENCE
它不会阻止它.并SFENCE
禁用此机制.
什么机制禁用LFENCE
无法重新排序(x86没有机制 - Invalidate-Queue)?
并且只是在理论上或者在现实中重新排序SFENCE
MOV reg, [addr]
- > MOV reg, [addr]
SFENCE
可能吗?如果可能,实际上,什么机制,它是如何工作的?