簡體   English   中英

在 64 位 x64/Amd64 處理器上執行 8 位和 64 位指令的時序

[英]Timing of executing 8 bit and 64 bit instructions on 64 bit x64/Amd64 processors

8 it 和 64 位指令在 64 位 x64/Amd64 處理器上是否有任何執行時序差異,當這些指令除了位寬之外是相似/相同時? 有沒有辦法找到執行這兩個微型匯編函數的真實處理器時序?

-謝謝。

; 64 bit instructions
add64:
     mov  $0x1, %rax
     add  $0x2, %rax
     ret

; 8 bit instructions
add8:
     mov  $0x1, %al
     add  $0x2, %al
     ret

是的,有區別。 mov $0x1, %al在大多數 CPU 上對 RAX 的舊值有錯誤的依賴,包括比 Sandybridge 更新的所有 CPU。 這是一個2輸入1輸出指令; 從 CPU 的角度來看,它就像add $1, %al一樣獨立或不相對於 RAX 的其他用途進行調度。 僅寫入 32 位或 64 位寄存器會啟動新的依賴鏈。

這意味着您的add8 function 的 AL 返回值可能無法准備好,直到調用者在調用之前恰好在 EAX 中執行的某些獨立工作的緩存未命中后才准備好,但add64的 RAX 結果可能會立即准備好用於 out-of -order 執行以在調用者中使用返回值的后續指令上開始。 (假設他們的其他輸入也准備好了。)

它們的代碼大小也不同:兩條 8 位指令都是 2 個字節長。 (感謝 AL,imm8 短格式編碼; add $1, %dl將是 3 個字節)。 RAX 指令有 7 個和 4 個字節長。 這對於 L1i 緩存占用很重要(在大規模上,對於必須從磁盤調入多少字節)。 在小范圍內,如果 CPU 正在執行舊版解碼,那么 16 或 32 字節的提取塊可以容納多少條指令,因為代碼在 uop 緩存中還不是很熱。 后面指令的代碼對齊也會受到前面指令的不同長度的影響,有時會影響哪些分支相互別名。

https://agner.org/optimize/解釋了各種 x86 微架構的流水線細節,包括前端解碼效果,可以使指令長度不僅僅是 I-cache / uop-cache 中的代碼密度。

通常 32 位操作數大小是最有效的(就性能而言,並且對於代碼大小來說非常好) 32 和 8 是 x86-64 可以在沒有額外前綴的情況下使用的操作數大小,實際上使用 8 位來避免停頓和壞事,您需要更多指令或更長的指令,因為它們不會零擴展。 在 x86-64 中使用 32 位寄存器/指令的優點

對於 64 位操作數大小,ALU 中的一些指令實際上更慢,而不僅僅是前端效果。 這包括大多數 CPU 上的div和一些舊 CPU 上的imul 還有 popcnt 和 bswap。 例如,試除法代碼在 Windows 上運行 32 位比在 Linux 上運行 64 位快 2 倍

請注意, mov $0x1, %rax將使用 GAS 組裝成 7 個字節,除非您使用as -O2 (與gcc -O2不同,請參見示例)以使其優化為mov $1, %eax ,這正是相同的架構效果,但更短(沒有 REX 或 ModRM 字節)。 一些匯編程序默認情況下會進行優化,但 GAS 不會。 為什么 Linux 上的 NASM 更改 x86_64 程序集中的寄存器有更多關於為什么這種優化是安全和良好的,以及為什么你應該在源代碼中自己做,特別是如果你的匯編程序不為你做。


但是除了錯誤的 dep 和代碼大小之外,它們對於 CPU 的后端是相同的:所有這些指令都是單 uop 並且可以在任何標量整數 ALU 執行端口1上運行。 https://uops.info/對每條非特權指令的每種形式都有自動測試結果)。

腳注 1 :挖掘機(上一代 Bulldozer 系列)還可以在另外 2 個端口 (AGU) 上運行mov $imm, %reg ,用於 32 位和 64 位操作數大小。 但是將新的低 8 或低 16 合並到一個完整的寄存器中需要一個 ALU 端口。 所以mov $1, %rax在 Excavator 上有 4/clock 的吞吐量,但是mov $1, %al只有 2/clock 的吞吐量。 (當然,僅當您使用幾個不同的目標寄存器時,實際上不是重復使用 AL;這將是 1/clock 的延遲瓶頸,因為在該微架構上寫入部分寄存器會產生錯誤的依賴性。)

以前從 Piledriver 開始的 Bulldozer 系列 CPU 可以在 EX0、EX1、AGU0、AGU1 上運行mov reg, reg (用於 r32 或 r64),而包括mov $imm, %reg在內的大多數 ALU 指令只能在 EX0/1 上運行。 進一步擴展 AGU 端口的功能以處理 mov-immediate 是 Excavator 中的一項新功能。

幸運的是,推土機被 AMD 更好的 Zen 架構淘汰了,該架構具有 4 個全標量 integer ALU 端口/執行單元。 (還有一個更寬的前端和一個 uop 緩存,良好的緩存,並且通常不會像 Bulldozer 那樣糟糕。)


有沒有辦法測量它?

是的,但通常不在您使用call的 function 中。 而是把它放在一個展開的循環中,這樣你就可以用最少的其他指令運行它很多次。 查看 CPU 性能計數器結果以查找前端/后端 uop 計數以及循環的總時間特別有用。

您可以構建循環來測量延遲或吞吐量; 請參閱NASM 中的 RDTSCP 始終返回相同的值(計時單個指令) 還:

通常,您不需要測量自己(盡管了解如何測量很好,這有助於您了解測量的真正含義)。 人們已經為大多數 CPU 微架構做到了這一點。 您可以基於分析指令來預測特定 CPU 的某些循環的性能(如果您可以假設沒有停頓或緩存未命中)。 通常這可以相當准確地預測性能,但是 OoO exec 只能部分隱藏的中等長度的依賴鏈使得准確預測或解釋每個周期變得過於困難。

暫無
暫無

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

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