Assembly Hall of Shame
https://github.com/xoreaxeaxeax/asm-hall-of-shame📌 【Assembly Hall of Shame】挑戰指令延遲極限:誰是 CPU 單一指令效能的最差紀錄保持者?
TL;DR:這是一個挑戰指令執行延遲下限的專案,透過極端手段讓單一指令耗時數秒。
當工程師討論指令效能時,目標通常是「如何更快」;但在 Assembly Hall of Shame 專案中,目標完全相反:搜尋單一指令效能的「絕對地板」。
🤔 從效能優化轉向延遲極限挑戰
通常我們致力於優化程式碼以提升效能,但這個專案透過各種手段,試圖找出哪些指令在最極端的條件下,會導致 CPU 產生最長的等待時間。這不僅是技術上的趣味挑戰,也揭示了硬體架構在處理特定指令時的極端邊界。
🧩 x86 架構的當代冠軍:利用 PCIe 擁塞製造延遲
目前 x86 榜單上的冠軍展示了何謂「極致的慢」:
- 策略:使用
fxrstor64指令從高延遲的 PCIe MMIO 區域載入 512 位元組的 FPU/MMX/XMM 狀態,並同時利用一群核心對另一個高延遲 MMIO 暫存器進行密集的 4 位元組讀取,藉由飽和 PCIe 根複合物 (Root Complex) 與端點 (Endpoint) 的非發送 (non-posted) 交易,讓fxrstor64必須在擁塞的流量中排隊。 - 測試平臺:AMD Ryzen 7 5800H
- 🏆 評分:198,002,498,236 cycles
- ⏱️ 耗時:62 秒
⚠️ 規則說明 為了公平比較,該專案制定了嚴格規則:
- 僅限單一指令計分(可進行任何必要的準備工作)。
- 被陷阱 (trapped)、模擬 (emulated) 或虛擬化 (virtualized) 的指令,僅能計算陷阱本身的耗時,而非處理程序 (handler) 的時間。
- 不得使用可中斷的指令(如
rep movs、pause等)。 - 所有的時間數據皆根據 CPU 基準時脈進行歸一化。
📊 x86 榜單節選:從微秒到毫秒的指令延遲
以下列出部分具有代表性的指令及其延遲表現:
| 排名 | 指令 | 策略摘要 | 耗時 |
|---|---|---|---|
| 7 | in | 針對映射至 ACPI PM 區塊的 I/O 埠,觸發多次非發送載入 | 3.921 ms |
| 8 | wbinvd | 填滿 L1/L2/L3 快取並強制將髒資料寫回 DRAM | 506.165 μs |
| 10 | rdmsr | 使用未經文件說明的暫存器 (VIA Eden 處理器) | 202.004 μs |
| 12 | wrmsr | 觸發微碼同步 (microcode quiesce) 與硬體單元間的通訊 | 10.742 μs |
| 14 | cpuid | 尋找具備最高延遲的 CPUID leaves | 460 ns |
| 17 | fadd | 使用次正規化 (subnormal) 運算元觸發浮點微碼輔助 | 249 ns |
| 24 | idiv | 使用大於 64 位元除法結果範圍的除法,強迫微碼執行最長路徑 | 28 ns |
🎯 實務啟示
透過這項專案,底層工程師可以觀察到硬體在處理極端邊界情況(如次正規化數值、I/O 埠邊界、或 PCIe 擁塞)時的行為。了解這些「最慢指令」的觸發條件,對於開發極高時效性的系統(如即時系統或高效能運算)在進行效能預測與邊界測試時,具有重要的參考價值。
🔗 來源
- 標題:Assembly Hall of Shame
- 連結:https://github.com/xoreaxeaxeax/asm-hall-of-shame
#Assembly #x86 #LowLevel #CPU #Microcode #Performance #AMD #Intel #ComputerArchitecture #ComputerScience
原始資料 Hacker News · 收集於 2026-08-08
摘要原文
Assembly Hall of Shame Overview Instruction latency analysis usually focuses on performance optimization —making code run as fast as possible. The Assembly Hall of Shame takes the opposite approach: searching for the absolute floor of single-instruction performance. 🏆 Current Champions 🏆 x86 : fxrstor64 Strategy : Use fxrstor64 to load 512-byte FPU/MMX/XMM state from a high-latency MMIO region in the PCIe fabric, then starve the fabric while the load is in flight — a fleet of hammer cores pounds a different high-latency MMIO register with tight 4-byte reads, saturating the PCIe root complex and endpoint with non-posted transactions, so CPU 0's 512-byte fxrstor64 must queue behind all that contending traffic. Contender : AMD Ryzen 7 5800H ; CPU 0 — timed instruction movl $ 0xfcc68830 , % rsi fxrstor64 % rsi ; CPUs 1..N — hammer loop against a different high-latency location movl 0xfcc68858 , % eax 🏆 Score : 198,002,498,236 cycles 🏆 Time : 62 seconds Honorable Mentions A spec-violating unaligned ymm0 load that forced non-posted dword transactions from stalled GPU registers was used to break the fundamental design of System Management Mode in smiiiiiiiiiiiiiiii . vmovdqu 0xfcc003b1 , % ymm0 Rules Instructions may use whatever setup is necessary, but only a single instruction is eligible to be scored. Trapped/emulated/virtualized instructions may only time the trap, not the handler. Instructions must not be interruptible. rep movs , pause , etc. are disqualified. Times are normalized based on the CPU base clock frequency. All platforms must be in their factory stock configurations - no hardware modifications. x86 Leaderboard 27. nop Strategy : nop does nothing. It opens the leaderboard accordingly. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz nop Score : 1 cycles Time : 0 nanoseconds 26. nop16 Strategy : Regular nop was too short, but how do we make nothing take longer? Try a lonnnnnng nop . Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz data16 data16 data16 data16 data16 data16 data16 nopl 0x00000000(%%eax,%%eax,1) Score : 20 cycles Time : 7 nanoseconds 25. rdtsc Strategy : Just a reference instruction to get our bearings. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz rdtsc Score : 49 cycles Time : 18 nanoseconds 24. idiv Strategy : Use 128-bit dividend (rdx:rax=2:0) with small divisor to push the quotient above the ceiling imposed by sign-extension, driving the longest path through the divider microcode. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz xorq % rax , % rax ; rax = 0 (low 64 bits of dividend) movq $ 2 , % rdx ; rdx = 2 (high 64 bits: full dividend = 2^65) movq $ 5 , % rbx ; divisor → quotient = 2^65/5 ≈ 7.4×10^18 idivq % rbx Score : 77 cycles Time : 28 nanoseconds 23. enter Strategy : Use maximum nesting depth (31) to force 30 display-pointer loads and pushes through the microcode display-walk path. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz enter $ 0 , $ 31 ; 0 bytes allocated, nesting depth 31 (maximum) Score : 112 cycles Time : 41 nanoseconds 22. fldl Strategy : Try a small denormal to trigger an FP microcode assist. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz movabsq $ 0x0000000000000001 , % rax movq % rax , - 8 (% rsp ) fldl - 8 (% rsp ) Score : 133 cycles Time : 49 nanoseconds 21. clflush Strategy : Just ensure the cache line is dirty. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz clflush (% rax ) ; rax -> dirty cache line resident in L3 Score : 165 cycles Time : 60 nanoseconds 20. fsin Strategy : Use exponent 0x7ff to reach 'special value' processing in microcode; positive/negative, NaN/inf doesn't seem to make a difference, go with QNaN. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz movabsq $ 0x7fffffffffffffff , % rax movq % rax , - 8 (% rsp ) fldl - 8 (% rsp ) fsin Score : 257 cycles Time : 94 nanoseconds 19. mfence Strategy : Saturate all write-combining line-fill buffers with movnti stores to distinct cache lines, forcing mfence to drain the full LFB write path to the uncore before retiring. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz movnti % r9 , 0 * 64 (% rdi ) ; ×16 distinct cache lines — saturate the write-combining LFBs ; … movnti % r9 , 15 * 64 (% rdi ) mfence ; must drain all pending LFB writes before retiring Score : 326 cycles Time : 120 nanoseconds 18. mov cr3 Strategy : Nothing for now, just check how long it takes to invalidate the TLB. Contender : AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5) mov % rax , % cr3 Score : 352 cycles Time : 110 nanoseconds 17. fadd Strategy : Hit x87 FP microcode assist path by using denormal source operand. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz fldl subnorm ; 1e-310: value < DBL_MIN, biased exponent = 0 faddl subnorm ; source is subnormal → FP microcode assist Score : 677 cycles Time : 249 nanoseconds 16. split lock Strategy : Align lock -prefixed operand to straddle cache-line boundary, forcing CPU to assert the external bus lock rather than using the fast MESI cache-coherence path. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz ; split_ptr % 64 == 63 — dword spans bytes 63 (line N) and 64–66 (line N+1) lock xaddl % r9d , (% rdi ) Score : 865 cycles Time : 319 nanoseconds 15. fdiv - Strategy : Use subnormal divisor, hardware hands control to microcode assist, assist normalizes operand, performs the division, then restores architectural state. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz movabsq $ 0x3ff0000000000000 , % rax ; 1.0 (normal dividend) movq % rax , - 8 (% rsp ) fldl - 8 (% rsp ) ; ST(0) = 1.0 movabsq $ 0x0000002000000000 , % rax ; 6.79e-313 (subnormal divisor) movq % rax , - 8 (% rsp ) fdivl - 8 (% rsp ) ; ST(0) = 1.0 / subnormal → FP assist Score : 883 cycles Time : 325 nanoseconds 14. cpuid Strategy : Use rakefield to find the highest latency CPUID leaves. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz movl $6, %eax cpuid Score : 1248 cycles Time : 460 nanoseconds 13. rdrand Strategy : Execute in a tight loop to deplete the hardware entropy pool faster than it can be refilled, forcing subsequent calls to stall while the entropy source recovers. Contender : Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz rdrand % rax Score : 5,579 cycles Time : 2.057 microseconds 12. wrmsr Strategy : Use project:nightshyft to identify high latency MSRs. MCG_CTL on Zen look like a winner: may be a microcode quiesce and synchronize on MCA error banks across hardware units, some potentially off-die, requiring fabric-level communication rather than a simple local register write. Contender : AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5) movl $ 0x17b , % ecx ; MCG_CTL wrmsr Score : 34,304 cycles Time : 10.742 microseconds 11. out Strategy : Target an I/O port that straddles a NIC device register boundary, triggering the device to quiesce its TX DMA engine on each write. Contender : AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5) mov $ 0xf019 , % dx outl % eax , % dx Score : 49,857 cycles Time : 15.580 microseconds 10. rdmsr Strategy : Use project:nightshyft to identify high latency model-specific-registers: VIA uses an undocumented register at 0x133 that gives wildly high response time. No idea what it does. Contender : VIA Eden Processor 800MHz movl $ 0x133 , % ecx ; undocumented MSR rdmsr Score : 161,602 cycles Time : 202.004 microseconds 9. wbinvd Strategy : Fully load L1/L2/L3 caches with dirty lines to force DRAM writeback of entire hierarchy. Contender : AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5) wbinvd Score : 1,616,480 cycles Time : 506.165 microseconds 8. in Strategy : Target I/O port mapped to an ACPI PM block where an unaligned 4-byte read decodes into multiple non-posted loads from wherever this port goes. Contender : AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5) mov $ 0x0413 , % dx inl % dx , % eax Score : 12,524,415 cycles Time : 3.921769 milliseconds 7. (304 points, 71 comments on Hacker News)
由 tencent/hy3:free 自動生成