忙环和屏障
Busy loop and the barrier
void loop(int loops)
{
while (loops-- > 0)
asm volatile ("" : : : "memory")
}
我知道 asm volatile ("" : : : "memory")
会阻止编译器重新排序指令。但是,在这里,我看不到可以重新排序的内容以及为什么它在并发方面可能会出现问题。 (我考虑了可能的中断)。那么,为什么会有障碍呢?
其次,连接问题。
假设我们有一段 10000000 行的代码(见下文)。我们知道 CPU 可以重新排序 StoreLoad。
mov [eax], $2;
不;
不;
...;
不;
mov ebx, [ecx];
CPU 能够预测应用 StoreLoad 的机会有多深?
同样的问题可以应用于编译器,但它涉及各种重新排序(不仅是StoreLoad而且不仅仅是内存操作)
TL:DR:这里的问题是你只是把它想成 std::atomic_thread_fence(std::memory_order_seq_cst)
,但这不是 GNU C [=12= 的唯一东西] 声明做。
是的,很明显障碍是存在一个令人讨厌的忙等待延迟循环。请记住,volatile asm
语句不能与任何其他 C 语句一起重新排序,不仅仅是内存操作。
void loop_nomemclobber(int loops) {
do { // loop rearranged for simpler asm
asm volatile ("" : : : /* "memory" */ );
} while (--loops > 0);
}
loop_nomemclobber:
.L3:
sub edi, 1
test edi, edi
jg .L3
ret
即使不强制所有可访问的内存都是最新的并被视为已损坏,我们仍然会遇到循环。所以 asm volatile
语句这样做的原因与 "memory"
破坏无关。
int loops
是一个带有自动存储的本地。编译器可以证明没有任何东西(包括 asm 语句)可以确定它可能在内存中的位置,因此它根本不必在内存中。
How deeply does the CPU is able to predict that there is a chance to apply StoreLoad?
CPU 不会无缘无故地寻找机会重新排序内存!重新排序自然发生(除非使用 MFENCE 阻止),因为 CPU 需要缓冲存储,直到确定它们不是推测性的,并且在缓存未命中存储上。所以它将存储放在存储缓冲区中,它们最终提交给缓存。
CPU话里没有小恶魔"aha, here's another chance to make things difficult for Gilgamesz, maybe I'll really trick him this time with this reordering!"
这里有一个真正的问题,那就是 在一个特定的指令之前,两条指令需要相隔多远(在时间上,或在 insn 的数量上,或在中间的数量上 loads/stores)微体系结构没有足够的无序资源供该存储缓冲,直到加载之后。
我不知道,但由于不允许 StoreStore 重新排序,因此无法在数百万其他指令的同时等待对高速缓存行的访问,从而导致高度竞争的缓存行的缓存未命中存储运行。除非这些指令中的 none 是商店。
我不知道答案,但我认为存储理论上可以在 Intel Haswell 上延迟数百万个周期是合理的,可能仅受处理以下情况的硬件仲裁机制的公平算法的限制多个内核争用同一缓存行。
我忘记了我读过的关于现代英特尔硬件是否以这种方式工作的内容,但我认为也许商店可以从无序核心中退出但仍然没有致力于 L1 缓存。相反,它只是在商店队列中作为肯定会发生的商店。这将使缓存未命中存储避免阻止新指令进入 ROB。 (加载需要探测存储缓冲区以保持单核内的正确执行,但这样做不需要 ROB 也跟踪存储)。
void loop(int loops)
{
while (loops-- > 0)
asm volatile ("" : : : "memory")
}
我知道
asm volatile ("" : : : "memory")
会阻止编译器重新排序指令。但是,在这里,我看不到可以重新排序的内容以及为什么它在并发方面可能会出现问题。 (我考虑了可能的中断)。那么,为什么会有障碍呢?其次,连接问题。 假设我们有一段 10000000 行的代码(见下文)。我们知道 CPU 可以重新排序 StoreLoad。
mov [eax], $2; 不; 不; ...; 不; mov ebx, [ecx];
CPU 能够预测应用 StoreLoad 的机会有多深?
同样的问题可以应用于编译器,但它涉及各种重新排序(不仅是StoreLoad而且不仅仅是内存操作)
TL:DR:这里的问题是你只是把它想成 std::atomic_thread_fence(std::memory_order_seq_cst)
,但这不是 GNU C [=12= 的唯一东西] 声明做。
是的,很明显障碍是存在一个令人讨厌的忙等待延迟循环。请记住,volatile asm
语句不能与任何其他 C 语句一起重新排序,不仅仅是内存操作。
void loop_nomemclobber(int loops) {
do { // loop rearranged for simpler asm
asm volatile ("" : : : /* "memory" */ );
} while (--loops > 0);
}
loop_nomemclobber:
.L3:
sub edi, 1
test edi, edi
jg .L3
ret
即使不强制所有可访问的内存都是最新的并被视为已损坏,我们仍然会遇到循环。所以 asm volatile
语句这样做的原因与 "memory"
破坏无关。
int loops
是一个带有自动存储的本地。编译器可以证明没有任何东西(包括 asm 语句)可以确定它可能在内存中的位置,因此它根本不必在内存中。
How deeply does the CPU is able to predict that there is a chance to apply StoreLoad?
CPU 不会无缘无故地寻找机会重新排序内存!重新排序自然发生(除非使用 MFENCE 阻止),因为 CPU 需要缓冲存储,直到确定它们不是推测性的,并且在缓存未命中存储上。所以它将存储放在存储缓冲区中,它们最终提交给缓存。
CPU话里没有小恶魔"aha, here's another chance to make things difficult for Gilgamesz, maybe I'll really trick him this time with this reordering!"
这里有一个真正的问题,那就是 在一个特定的指令之前,两条指令需要相隔多远(在时间上,或在 insn 的数量上,或在中间的数量上 loads/stores)微体系结构没有足够的无序资源供该存储缓冲,直到加载之后。
我不知道,但由于不允许 StoreStore 重新排序,因此无法在数百万其他指令的同时等待对高速缓存行的访问,从而导致高度竞争的缓存行的缓存未命中存储运行。除非这些指令中的 none 是商店。
我不知道答案,但我认为存储理论上可以在 Intel Haswell 上延迟数百万个周期是合理的,可能仅受处理以下情况的硬件仲裁机制的公平算法的限制多个内核争用同一缓存行。
我忘记了我读过的关于现代英特尔硬件是否以这种方式工作的内容,但我认为也许商店可以从无序核心中退出但仍然没有致力于 L1 缓存。相反,它只是在商店队列中作为肯定会发生的商店。这将使缓存未命中存储避免阻止新指令进入 ROB。 (加载需要探测存储缓冲区以保持单核内的正确执行,但这样做不需要 ROB 也跟踪存储)。