Hacker News ★ 73 3 min

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 movspause 等)。
  • 所有的時間數據皆根據 CPU 基準時脈進行歸一化。

📊 x86 榜單節選:從微秒到毫秒的指令延遲

以下列出部分具有代表性的指令及其延遲表現:

排名指令策略摘要耗時
7in針對映射至 ACPI PM 區塊的 I/O 埠,觸發多次非發送載入3.921 ms
8wbinvd填滿 L1/L2/L3 快取並強制將髒資料寫回 DRAM506.165 μs
10rdmsr使用未經文件說明的暫存器 (VIA Eden 處理器)202.004 μs
12wrmsr觸發微碼同步 (microcode quiesce) 與硬體單元間的通訊10.742 μs
14cpuid尋找具備最高延遲的 CPUID leaves460 ns
17fadd使用次正規化 (subnormal) 運算元觸發浮點微碼輔助249 ns
24idiv使用大於 64 位元除法結果範圍的除法,強迫微碼執行最長路徑28 ns

🎯 實務啟示

透過這項專案,底層工程師可以觀察到硬體在處理極端邊界情況(如次正規化數值、I/O 埠邊界、或 PCIe 擁塞)時的行為。了解這些「最慢指令」的觸發條件,對於開發極高時效性的系統(如即時系統或高效能運算)在進行效能預測與邊界測試時,具有重要的參考價值。

🔗 來源

#Assembly #x86 #LowLevel #CPU #Microcode #Performance #AMD #Intel #ComputerArchitecture #ComputerScience

原始資料 Hacker News · 收集於 2026-08-08
來源原標題
Assembly Hall of Shame
作者
piotrgrabowski
原始標籤
hackernews
來源訊號
HN points 304 HN 留言 71
原始連結
https://github.com/xoreaxeaxeax/asm-hall-of-shame

摘要原文

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 自動生成