プログラミング
Assembly Hall of Shame
Assembly Hall of Shame (github.com)
要約
「Assembly Hall of Shame」は、単一命令のパフォーマンスの絶対的な最低ラインを追求するプロジェクトです。x86アーキテクチャでは、fxrstor64命令がPCIeファブリックの遅延を利用して、198,002,498,236サイクルという驚異的な実行時間を記録し、現在のチャンピオンとなっています。このプロジェクトでは、意図的に命令の実行時間を長くする方法を探求しています。
全文翻訳
Assembly Hall of Shame
概要
レイテンシ分析は通常、コードを可能な限り高速に実行するためのパフォーマンス最適化に焦点を当てます。「Assembly Hall of Shame」は、その逆のアプローチを取ります。単一命令のパフォーマンスの絶対的な最低ラインを追求します。
🏆 現在のチャンピオン 🏆
x86: fxrstor64
戦略: fxrstor64を使用して、PCIeファブリック内の高レイテンシMMIO領域から512バイトのFPU/MMX/XMM状態をロードします。その後、ロードが進行中にファブリックを枯渇させます。多数のコアが、投稿されないトランザクションでPCIeルートコンプレックスとエンドポイントを飽和させる別の高レイテンシMMIOレジスタをタイトな4バイト読み取りで攻撃します。これにより、CPU 0の512バイトのfxrstor64は、その競合トラフィックのすべてをキューイングしなければならなくなります。
対戦相手: AMD Ryzen 7 5800H; CPU 0 — タイミングされた命令
movl $0xfcc68830, %rsi
fxrstor64 %rsi
; CPUs 1..N — 別の高レイテンシの場所にハンマーループ
movl 0xfcc68858, %eax
🏆 スコア: 198,002,498,236 サイクル 🏆
時間: 62 秒
栄誉賞
GPUレジスタの停止によって引き起こされた、非投稿型dwordトランザクションを強制した仕様違反の非アラインメントymm0ロードが、smiiiiiiiiiiiiiiiiにおけるシステム管理モードの基本的な設計を破壊するために使用されました。
vmovdqu 0xfcc003b1, %ymm0
ルール
命令は必要なセットアップをすべて使用できますが、スコアリングの対象となるのは単一の命令のみです。
トラップされた/エミュレートされた/仮想化された命令は、ハンドラーではなくトラップのみをタイミングできます。
命令は割り込み可能であってはなりません。
rep movs, pauseなどは失格となります。
時間はCPUのベースクロック周波数に基づいて正規化されます。
すべてのプラットフォームは工場出荷時の構成である必要があります - ハードウェアの変更はありません。
x86 リーダーボード
27. nop
戦略: nopは何もしません。リーダーボードをそれに応じて開きます。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
nop
スコア: 1 サイクル
時間: 0 ナノ秒
26. nop16
戦略: 通常のnopは短すぎましたが、何もしないことをより長くするにはどうすればよいでしょうか?長いnopを試してみてください。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
data16 data16 data16 data16 data16 data16 data16
nopl 0x00000000(%%eax,%%eax,1)
スコア: 20 サイクル
時間: 7 ナノ秒
25. rdtsc
戦略: 方向感覚を得るための単なる参照命令です。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
rdtsc
スコア: 49 サイクル
時間: 18 ナノ秒
24. idiv
戦略: 128ビットの被除数(rdx:rax=2:0)と小さな除数を使用して、商を符号拡張によって課される上限を超えさせ、除算器マイクロコードの最も長いパスを駆動します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
xorq %rax, %rax ; rax = 0 (被除数の下位64ビット)
movq $2, %rdx ; rdx = 2 (上位64ビット: 完全な被除数 = 2^65)
movq $5, %rbx ; 除数 → 商 = 2^65/5 ≈ 7.4×10^18
idivq %rbx
スコア: 77 サイクル
時間: 28 ナノ秒
23. enter
戦略: 最大ネスト深度(31)を使用して、マイクロコードのディスプレイウォークパスを通じて30個のディスプレイポインタのロードとプッシュを強制します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
enter $0, $31 ; 0 バイト割り当て、ネスト深度 31 (最大)
スコア: 112 サイクル
時間: 41 ナノ秒
22. fldl
戦略: FPマイクロコードアシストをトリガーするために小さな非正規数を試します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
movabsq $0x0000000000000001, %rax
movq %rax, -8(%rsp)
fldl -8(%rsp)
スコア: 133 サイクル
時間: 49 ナノ秒
21. clflush
戦略: キャッシュラインがダーティであることを確認します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
clflush (%rax) ; rax -> L3に常駐するダーティキャッシュライン
スコア: 165 サイクル
時間: 60 ナノ秒
20. fsin
戦略: 指数0x7ffを使用して「特殊値」処理にマイクロコードで到達します。正/負、NaN/infは関係ないようです。QNaNを使用します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
movabsq $0x7fffffffffffffff, %rax
movq %rax, -8(%rsp)
fldl -8(%rsp)
fsin
スコア: 257 サイクル
時間: 94 ナノ秒
19. mfence
戦略: movntiストアを使用して書き込み結合ラインフィルバッファをすべて異なるキャッシュラインに飽和させ、mfenceがフルLFB書き込みパスをアンコアにドレインしてからリタイアするように強制します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
movnti %r9, 0*64(%rdi) ; ×16 個の異なるキャッシュライン — 書き込み結合LFBを飽和させる
; …
movnti %r9, 15*64(%rdi)
mfence ; リタイア前にすべての保留中のLFB書き込みをドレインする必要がある
スコア: 326 サイクル
時間: 120 ナノ秒
18. mov cr3
戦略: 現時点では何もありません。TLBを無効にするのにどれくらいの時間がかかるかを確認するだけです。
対戦相手: AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)
mov %rax, %cr3
スコア: 352 サイクル
時間: 110 ナノ秒
17. fadd
戦略: 非正規ソースオペランドを使用してx87 FPマイクロコードアシストパスにヒットします。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
fldl subnorm ; 1e-310: 値 < DBL_MIN, バイアス付き指数 = 0
faddl subnorm ; ソースは非正規 → FPマイクロコードアシスト
スコア: 677 サイクル
時間: 249 ナノ秒
16. split lock
戦略: lockプレフィックス付きオペランドをキャッシュライン境界をまたぐようにアラインメントし、CPUが高速MESIキャッシュコヒーレンスパスを使用する代わりに外部バスロックをアサートするように強制します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
; split_ptr % 64 == 63 — dwordはバイト63 (ラインN) と64–66 (ラインN+1) にまたがる
lock xaddl %r9d, (%rdi)
スコア: 865 サイクル
時間: 319 ナノ秒
15. fdiv
戦略: 非正規除数を使用します。ハードウェアはマイクロコードアシストに制御を渡します。アシストはオペランドを正規化し、除算を実行し、その後アーキテクチャ状態を復元します。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
movabsq $0x3ff0000000000000, %rax ; 1.0 (正規の被除数)
movq %rax, -8(%rsp)
fldl -8(%rsp) ; ST(0) = 1.0
movabsq $0x0000002000000000, %rax ; 6.79e-313 (非正規除数)
movq %rax, -8(%rsp)
fdivl -8(%rsp) ; ST(0) = 1.0 / 非正規 → FPアシスト
スコア: 883 サイクル
時間: 325 ナノ秒
14. cpuid
戦略: rakefieldを使用して、最もレイテンシの高いCPUIDリーフを見つけます。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
movl $6, %eax
cpuid
スコア: 1248 サイクル
時間: 460 ナノ秒
13. rdrand
戦略: タイトなループで実行し、ハードウェアエントロピープールが補充されるよりも速く枯渇させ、エントロピーソースが回復するのを待つように後続の呼び出しをブロックさせます。
対戦相手: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
rdrand %rax
スコア: 5,579 サイクル
時間: 2.057 マイクロ秒
12. wrmsr
戦略: project:nightshyftを使用して、高レイテンシMSRを特定します。ZenのMCG_CTLは勝者のようです。マイクロコードのクワイエットと、ハードウェアユニット間のMCAエラーバンクの同期を行う可能性があります。一部はオフダイである可能性があり、単純なローカルレジスタ書き込みではなく、ファブリックレベルの通信が必要です。
対戦相手: AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)
movl $0x17b, %ecx ; MCG_CTL
wrmsr
スコア: 34,304 サイクル
時間: 10.742 マイクロ秒
11. out
戦略: NICデバイスレジスタ境界をまたぐI/Oポートをターゲットにし、各書き込み時にデバイスがTX DMAエンジンをクワイエットするようにトリガーします。
対戦相手: AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)
mov $0xf019, %dx
পরিমাণl %eax, %dx
スコア: 49,857 サイクル
時間: 15.580 マイクロ秒
10. rdmsr
戦略: project:nightshyftを使用して、高レイテンシのモデル固有レジスタを特定します。VIAは0x133にある文書化されていないレジスタを使用しており、非常に高い応答時間を示します。それが何をするのかは不明です。
対戦相手: VIA Eden Processor 800MHz
movl $0x133, %ecx ; 文書化されていないMSR
rdmsr
スコア: 161,602 サイクル
時間: 202.004 マイクロ秒
9. wbinvd
戦略: L1/L2/L3キャッシュをダーティラインで完全にロードし、階層全体のDRAM書き戻しを強制します。
対戦相手: AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)
wbinvd
スコア: 1,616,480 サイクル
時間: 506.165 マイクロ秒
8. in
戦略: ACPI PMブロックにマップされたI/Oポートをターゲットにします。ここで非アラインメント4バイト読み取りが、このポートがどこへ行くのか分からない複数の非投稿型ロードにデコードされます。
対戦相手: AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)
mov $0x0413, %dx
inl %dx, %eax
スコア: 12,524,415 サイクル
時間: 3.921769 ミリ秒
7. mov
戦略: mmioticを使用して、PCIeファブリック内の高レイテンシのデッドスペースを特定し、未知のGPUレジスタにヒットします。
対戦相手: AMD Ryzen 7 5800H with Radeon Graphics (Trigkey S5)
movl 0xfcc003b0, %esi
スコア: 443,937,696 サイクル
時間: 139.010268 ミリ秒
6. mov rax
戦略: MMIO空間で最も遅いレジスタを検索します