英特爾內存模型保證:Intel內存模型是否使SFENCE和LFENCE冗餘?
- 店將不被重新排序,與其他百貨
- 負載不會重新排序與其它負載
http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/
我有由於英特爾存儲器模型,但從來沒有LFENCE認爲SFENCE在x86-64上是冗餘的。上述內存模型規則是否使指令冗餘?
英特爾內存模型保證:Intel內存模型是否使SFENCE和LFENCE冗餘?
http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/
我有由於英特爾存儲器模型,但從來沒有LFENCE認爲SFENCE在x86-64上是冗餘的。上述內存模型規則是否使指令冗餘?
是的,除了使用movnt
(非時間性)流式存儲或者將類型設置爲非正常回寫以外的其他存儲區域時,SFENCE和LFENCE不可操作。 NT商店繞過緩存以及弱排序(但是x86's normal memory model is strongly ordered(除了參見下面的Fast-String操作))。 (來自WB存儲器的NT加載(movntdqa
)爲still strongly ordered,因此LFENCE僅在從弱排序存儲器讀取時有用)。這不會在「正常」程序中偶然發生,所以如果你使用mmap視頻RAM或其他東西,你只需要擔心這一點。
此帖子:Memory Reordering Caught in the Act是一個易於閱讀的同一案例的描述Bartosz的文章談到,你需要像MFENCE這樣的StoreLoad障礙。
如果您在閱讀您發佈的鏈接後遇到問題,請閱讀Jeff Preshing的博客文章。他們讓我對這個問題有了很好的理解。 :)儘管我認爲我發現了有關SFENCE/LFENCE通常在Doug Lea的頁面中沒有任何操作的消息。傑夫的帖子並沒有考慮NT裝載/商店。
我好奇這幾個星期前,並張貼了相當詳細的解答到最近的問題: Atomic operations, std::atomic<> and ordering of writes。我包含了很多關於C++內存模型與硬件內存模型的鏈接。
如果您使用C++編寫,使用std::atomic<>
是一種很好的方式來告訴編譯器您有什麼排序要求,所以它不會在編譯時重新排序內存操作。您可以並應該使用較弱的版本,或者在適當的情況下獲取語義,而不是缺省的順序一致性,因此編譯器在x86上不必發出任何屏障指令。它只需要保持操作源的順序。
像ARM或PPC,或movnt的x86弱有序的架構,你需要寫一個緩衝區,設置標誌來表示數據已經準備好之間的StoreStore屏障指令。另外,閱讀器在檢查標誌和讀取緩衝區之間需要LoadLoad barrier指令。
不計算movnt,x86已經在每個負載和每個商店之間的StoreStore屏障之間存在LoadLoad屏障。 (LoadStore訂購也保證)。 MFENCE
是所有4種障礙,包括StoreLoad,這是x86默認情況下不會執行的唯一屏障。 MFENCE確保裝載不會在其他線程看到您的商店之前使用舊的預取值,並且可能確實存有自己的商店。 (以及成爲NT商店訂購和加載順序的障礙)。
有趣的事實:x86 lock
- 前綴指令也是完全內存障礙。它們可以用作舊式32位代碼中MFENCE的替代品,可以在不支持它的CPU上運行。lock add [esp], 0
否則爲空操作,並且在內存上執行讀取/修改/寫入循環,這在L1高速緩存中很可能很熱並且已經處於MESI一致性協議的M狀態。
SFENCE是StoreStore的障礙。
LFENCE是LoadLoad和also a LoadStore barrier。 (loadNT/LFENCE/storeNT
阻止商店從負載之前成爲全局可見,我認爲這可能在實踐中發生,如果加載地址是一個長期依賴鏈,或者在高速緩存又一次錯過了負載的結果的結果。)
有趣的事實#2(感謝@EOF
):Fast-String Ops(IvyBridge和更高版本上的rep stosb
/rep movsb
)的存儲是微弱排序的(但不包括緩存繞過)。
英特爾記錄了Fast-String Ops「在其軟件開發人員手冊」第1卷第7.3.9.3節中出現的「亂序執行」這一事實。他們還表示,
「的任何字符串操作之後,訂單相關的代碼應該寫爲離散信號變量 允許正確排序的數據可以看出 所有處理器」
他們不提任何障礙指示。我閱讀它的方式是,在rep stosb/rep movsb
之後有一個隱含的SFENCE(至少是一個字符串數據的柵欄,可能不是其他飛行中弱有序的NT)。無論如何,措辭意味着寫入標誌/信號變得全局可見在之後的所有字符串移動寫入,因此在用快速字符串op填充緩衝區然後寫入標誌的代碼中不需要SFENCE/LFENCE或者在讀取它的代碼中。 (LoadLoad的排序總是會發生的,所以你總能看到其他CPU使它全局可見的順序,即使用弱順序存儲來寫入緩衝區並不會改變其他線程中的負載仍然強烈排序的事實。)
摘要:使用正常的存儲區寫一個標誌,指示緩衝區已準備就緒。 沒有讀者只檢查用memset/memcpy寫入的塊的最後一個字節。不過,我認爲fast-string商店會阻止任何後來的商店通過它們,所以如果您使用的是movNT
,您仍然只需要使用SFENCE/LFENCE。
還有那些可以清除禁用快速串OPS,對於需要運行一個寫入「數據準備好」標誌爲rep stosb
或rep movsb
的一部分老的二進制文件的新服務器,造福CPU MSR位。
這不僅是'movnt',它的內存排序較弱。 memcpy/strcpy-instructions('rep [ne] movs [b/w/d/q]')也可以。 – EOF
@EOF:謝謝,我不知道!奇怪的是,insn參考手冊沒有提到,只有Vol1手冊。我更新了我的答案,並解釋了文檔的內容:在'rep movsb'後面有一個隱含的StoreStore屏障(對於字符串數據),因此您只需單獨編寫數據就緒標誌(而不是最後一個字節字符串op)。 –
@EOF:它不僅是'movnt'和'rep [ne] movs [b/w/d/q]';但是(可能)每一條訪問內存的指令;因爲可以通過爲被訪問的存儲器配置PAT /頁表或MTRR作爲「寫入組合」(而不是「寫回」)來削弱存儲器排序模型。 – Brendan
Err,Store-Load和Load-Store命令如何? –
@IwillnotexistIdonotexist:MFENCE是一個StoreLoad屏障(以及所有其他3種)。是的,你仍然需要它。 :P我不確定movNT加載/存儲是否可以顯示LoadStore重新排序,或者如果他們省略了單獨的LoadStore屏障指令,前提是您在需要LoadStore屏障時通常(總是)需要StoreLoad屏障。因爲無論如何它只會影響movnt流操作,這是一個特殊情況的特殊情況,如果沒有它,x86很好。 :P –
@PeterCordes [在之前的回答](http://stackoverflow.com/a/22142537/2809095)中,我引用了英特爾SDM的完整列表或允許重新排序。但是我在上面的評論中提到的是,OP大多正確地指出Load-Load和Store-Store重新排序不會發生。然而,這些只是總共四種可能性中的兩種(加載存儲和存儲加載是另外兩種組合),並且可能出現其他可能性,因此需要爲其提供「防護/防護/防護」功能。 –