簡體   English   中英

如何找到英特爾x86 CPU解碼指令的微操作?

[英]How can I find the micro-ops which instructions on Intel's x86 CPUs decode to?

英特爾優化參考,根據第3.5.1節,建議:

“贊成單微操作指令。”

“避免使用復雜指令(例如,輸入,離開或循環),這些指令超過4個微操作並需要多個周期才能解碼。請使用簡單指令序列。”

雖然英特爾自己告訴編譯器編寫者使用解碼為少數微操作的指令,但我在他們的任何手冊中都找不到任何東西,這解釋了每個ASM指令解碼的微操作數量! 這些信息是否隨處可用? (當然,我希望不同代CPU的答案會有所不同。)

Agner Fog關於x86指令的PDF 文檔 (鏈接主頁Hans引用)是我在指令時序和微操作上發現的唯一參考。 我從未見過關於微操作故障的英特爾文檔。

除了在其他答案( Agner Fog的表IACA )中已經提到的資源之外,您還可以在我們的網站uops.info上找到有關最新Intel CPU(從Nehalem到Cannon Lake)的大多數x86指令的μops的詳細信息。 該網站還包含有關每條指令的延遲和吞吐量的信息。 通過在實際硬件(使用硬件性能計數器)和不同版本的Intel IACA之上運行自動生成的微基准測試獲得數據。

相比於昂納霧的指示表上的數據uops.info是在一些情況下更准確和精確。 例如,考慮Nehalem上的PBLENDVB指令。 根據Agner Fog的表格,該指令有一個只能使用端口0的μop和一個只能使用端口5的μop。這可能是基於以下觀察結果:在單獨重復執行指令時,平均來說,端口0上有一個μop,端口5上有一個μop.uops.info上的微基准測試顯示實際上兩個μop都可以使用端口0和端口5.這是通過執行指令以及只能使用端口0或端口的指令來確定的。 5。

uops.info上的數據還揭示了英特爾IACA中的一些不准確之處。 例如,在SKYLAKE微架構的CVTPI2PS XMM,MM指令的兩個μops只能使用端口0在IACA( http://uops.info/html-ports/SKL/CVTPI2PS_XMM_MM-IACA3.0.html )。 在實際硬件上,有一個μop只能使用端口0,一個μop可以使用端口0和端口1.Agner Fog還觀察到該指令的一個μop可以使用端口1; 然而,他聲稱這個μop只能使用端口1,這是不正確的。

已經指出, Agner Fog的優化手冊是一個很好的資源,特別是他的指令表 ,它幾乎全面適用於所有感興趣的x86微體系結構。

但您確實有另一種選擇: 英特爾架構代碼分析器(IACA) 在Stack Overflow上有一篇關於如何使用它的文章,但它很容易上手(雖然對於一次性分析來說有點乏味)。 你只需下載可執行文件,在你想要分析的指令塊周圍發出一些序言和結尾代碼(它包含一個用於此目的的C頭( iacaMarks.h ),可以與各種編譯器一起使用,或者你可以指示你的匯編程序發出適當的字節),然后通過iaca.exe運行你的二進制iaca.exe 當前版本(v2.2)僅支持64位二進制文​​件,但這不是主要限制,因為對於32位和64位模式,指令級分析不會有太大差異。 當前版本還支持從Nehalem到Broadwell的專業軟件開發人員可能感興趣的所有現代英特爾微體系結構。

從此工具獲得的輸出將告訴您在指定的微體系結構上,特定指令可以執行哪些端口,以及該指令將分解到多少μop。

這就像你要直接回答你的問題一樣接近,因為正如Hans Passant在評論中指出的那樣 ,每條指令分解的確切μops被英特爾故意保密。 它們不僅是一個專有的商業秘密,而且英特爾希望能夠自由地改變它從一個微架構到另一個微架構的工作方式。 實際上,在優化代碼時,您只需要知道指令分解為多少 μops。 指令分解到哪個 μops並不重要。

但我會重申彼得·科德斯的答案的一部分“在某些情況下很容易猜到” 如果您必須為您正在考慮的每條指令查找此類詳細信息,您將浪費大量時間。 你也會瘋狂,因為你已經知道,它從一個微體系結構到另一個體系結構都有所不同。 這里的真正訣竅是直觀地了解x86 ISA中的哪些指令“簡單”且“復雜”。 通過閱讀文檔應該非常明顯,這種直觀的感覺實際上是英特爾的優化建議所帶來的。 避免使用“復雜”(舊的CISC風格)指令,如LOOPENTERLEAVE等。 例如, JNZ選擇DEC + JNZ不是LOOP 相對而言,只有少數“經典”x86指令可以解碼為超過一個或兩個μop。 *研究優秀編譯器的輸出也會引導您朝着正確的方向前進,因為您永遠不會看到編譯器使用這些“復雜”指令。

但是,彼得的回答有點不合適,我很確定英特爾優化手冊的引用部分並未提及SIMD指令。 他們談論的是在微代碼中實現的舊式CISC指令,如果他們不必支持它們以實現向后兼容性,那么它們就已經丟失了。 如果您需要SSE3的HADDPS的行為,那么您可能最好使用HADDPS而不是試圖將其分解為“更簡單”的組件。 (當然,除非您可以通過在不相關的代碼中交錯來更好地安排這些操作。但是在實踐中這很難做到。)


*為了完全准確,有些看似簡單的指令實際上是使用微碼實現的,並且分解為多個μop。 64位除法( DIV )就是一個例子。 如果我沒記錯的話,可以使用30-40μs(變量)進行微編碼。 但是,這不是您應該避免的說明,這表明英特爾的手冊在此處提供的建議非常普遍。 如果您需要進行划分,請使用DIV 在優化速度時,顯然更喜歡進行划分,但是不要試圖編寫自己的划分算法,以避免微編碼DIV

另一個很大的例外是字符串指令 然而,這些的性能計算比“避免因為它們解碼到多個μop”更復雜一些。

幸運的是,有一件事很簡單:永遠不要使用沒有 REP前綴的字符串指令。 這沒有意義,通過將指令“分解”為更簡單的“組件”指令,您將獲得更好的性能 - 例如, MOVSBMOV AL, [ESI] + MOV ES:[EDI], AL + INC/DEC ESI + INC/DEC EDI

當你開始利用REP前綴時,決定它有點棘手。 雖然這確實導致指令解碼成許多 μop,但有時使用重復的字符串指令比自己手動編碼循環更有效。 但不總是。 Stack Overflow和其他地方已經有很多關於這個問題的討論; 例如,看到這個問題

詳細的分析實際上超出了這個答案的范圍,但我的快速經驗法則是你可以完全忘記REP LOADSREP SCASREP CMPS 另一方面, 當您需要重復相當多次時REP MOVSREP STOS非常有用。 始終使用盡可能大的字大小:32位的DWORD,64位的QWORD(但請注意, 在現代處理器上,使用MOVSB / STOSB可能會更好,因為它們可以在內部移動更大的數量甚至在所有這些條件得到滿足,如果你的目標有可用的向量指令,你可能想要驗證用向量移動實現移動/存儲不會更快。

另見第150頁的Agner Fog的一般建議

Agner Fog的insn表顯示了哪些端口微操作運行,這對性能至關重要。 它沒有准確顯示每個uop的作用,因為這不是你可以逆向工程的東西。 (即它在該端口上使用的執行單元)。

在某些情況下很容易猜到:Haswell上的haddps端口為1 haddps ,端口5為2 haddps 。顯然有2個shuffle(端口5)和FP-add(端口1)。 端口5上有許多其他執行單元,例如矢量布爾值,SIMD整數加法和大量標量整數,但考慮到haddps需要多個haddps ,很明顯英特爾用shuffle和常規“垂直”來實現它。 “加上uop。

有可能找出關於那些uops之間的依賴關系的東西(例如,它是2個shufps樣式的shuffle提供FP添加,還是shuffle-add-shuffle?)。 我們也不確定shuffle是否相互獨立:Haswell只有一個shuffle端口,因此資源沖突會給我們5c的總延遲,因為即使它們是獨立的,shuffle也不能並行運行。

兩個shuffle uops可能都需要兩個輸入,因此即使它們彼此獨立,比另一個更快地准備一個輸入也不會改善關鍵路徑的延遲(從較慢的輸入到輸出)。

如果有可能實現具有2個獨立單輸入shuffle的HADDPS,那么意味着在xmm1為常量的循環中的HADDPS xmm0,xmm1將僅對涉及xmm0的dep鏈增加4c的延遲。 我沒有測量,但我認為這不太可能; 幾乎可以肯定,它是兩個獨立的2輸入混音器,用於饋送ADDPS uop。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM