Memory Barrier in Compiler and CPU


Memory barrier, is a type of barrier and a class of instruction which causes a CPU or compiler to enforce an ordering constraint on memory operations issued before and after the barrier instruction.

之所以需要Memory barrier就是因為CPU Out-of-order execution 和 compiler reordering optimizations。

 

 

Compiler memory barrier
 
These barriers prevent a compiler from reordering instructions, they do not prevent reordering by CPU.
The GNU inline assembler statement
asm volatile("" ::: "memory");
 
or even
__asm__ __volatile__ ("" ::: "memory");
 
forbids GCC compiler to reorder read and write commands around it.
Intel ECC compiler uses "full compiler fence"
__memory_barrier()
 
intrinsics.
Microsoft Visual C++ Compiler:[8]
_ReadWriteBarrier()

 

Hardware memory barrier
 
Many architectures with SMP support have special hardware instruction for flushing reads and writes.
x86, x86-64
lfence (asm), void_mm_lfence(void)
sfence (asm), void_mm_sfence(void) [9]
mfence (asm), void_mm_mfence(void) [10]
ARMv7
dmb (asm)
對硬件memory barrier的更多理解

  1. 只有一個主體(CPU或DMA控制器)訪問內存時,無論如何也不需要barrier;但如果有兩個或更多主體訪問內存,且其中有一個在觀測另一個,就需要barrier了。
  2. IA32 CPU調用有lock前綴的指令,或者如xchg這樣的指令,會導致其它的CPU也觸發一定的動作來同步自己的Cache。CPU的#lock引腳鏈接到北橋芯片(North Bridge)的#lock引腳,當帶lock前綴的執行執行時,北橋芯片會拉起#lock電平,從而鎖住總線,直到該指令執行完畢再放開。 而總線加鎖會自動invalidate所有CPU對 _該指令涉及的內存的Cache,因此barrier就能保證所有CPU的Cache一致性。
  3. lock前綴(或cpuid、xchg等指令)使得本CPU的Cache寫入了內存,該寫入動作也會引起別的CPU invalidate其Cache。IA32在每個CPU內部實現了Snoopying(BUS-Watching)技術,監視着總線上是否發生了寫內存操作(由某個CPU或DMA控制器發出的),只要發生了,就invalidate相關的Cache line。 因此,只要lock前綴導致本CPU寫內存,就必將導致所有CPU去invalidate其相關的Cache line。

兩個地方可能除外:

  • 如果采用write-through策略,則根本不存在緩存一致性問題(Linux對全部內存采用write-back策略);
  • TLB也是Cache,但它的一致性(至少在IA32上)不能通過Snooping技術解決,而是要發送INVALIDATE_TLB_VECTOR這個IPI給其它的CPU。

 

MESI協議

M: Modified,已修改
E: Exclusive,排他
S: Shared,共享
I: Invalid,無效

IA32 的CPU實現了MESI協議來保證Cache coherence。 CPU的總線監測單元,始終監視着總線上所有的內存寫操作,以便隨時調整自己的Cache狀態。

-> Modified。 本CPU寫,則直接寫到Cache,不產生總線事物;其它CPU寫,則不涉及本CPU的Cache,其它CPU讀,則本CPU需要把Cache line中的數據提供給它,而不是讓它去讀內存。

-> Exclusive。只有本CPU有該內存的Cache,而且和內存一致。 本CPU的寫操作會導致轉到Modified狀態。

-> Shared。 多個CPU都對該內存有Cache,而且內容一致。任何一個CPU寫自己的這個Cache都必須通知其它的CPU。

-> Invalid。 一旦Cache line進入這個狀態,CPU讀數據就必須發出總線事物,從內存讀。


 

DMA寫策略

1. Write through策略。 這種情形比較簡單。

-> 本CPU寫內存,是write through的,因此無論什么時候DMA讀內存,讀到的都是正確數據。
-> DMA寫內存,如果DMA要寫的內存被本CPU緩存了,那么必須Invalidate這個Cache line。下次CPU讀它,就
直接從內存讀。

2. Write back策略。 這種情形相當復雜。

-> DMA讀內存。被本CPU總線監視單元發現,而且本地Cache中有Modified數據,本CPU就截獲DMA的內存讀操作,
把自己Cache Line中的數據返回給它。

-> DMA寫內存。而且所寫的位置在本CPU的Cache中,這又分兩種情況:

  • Cache Line狀態未被CPU修改過(即cache和內存一致),那么invalidate該cache line。
  • Cache Line狀態已經被修改過,又分2種情況:
    • DMA寫操作會替換CPU Cache line所對應的整行內存數據,那么DMA寫,CPU則invalidate自己的Cache Line。
    • DMA寫操作只替換Cache Line對應的內存數據的一部分,那么CPU必須捕獲DMA寫操作的新數據(即DMA想把它寫入內存的),用來更新Cache Line的相關部分。

http://en.wikipedia.org/wiki/Memory_ordering#Compiler_memory_barrier

http://www.cppblog.com/tx7do/archive/2011/08/30/154701.aspx

http://en.wikipedia.org/wiki/Memory_barrier


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM