Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
.NET 8 で既定で有効になった Dynamic PGO について
Search
neno
October 28, 2023
Technology
3
7.7k
.NET 8 で既定で有効になった Dynamic PGO について
.NET ラボ 2023/10/28 での発表資料
ブログ
https://blog.neno.dev/entry/2023/10/29/131336
neno
October 28, 2023
Tweet
Share
More Decks by neno
See All by neno
.NET 9 のパフォーマンス改善
nenonaninu
0
910
C# 13 / .NET 9 の新機能 (RC 1 時点)
nenonaninu
1
1.9k
Re:ゼロから始める Observability
nenonaninu
3
810
Node-AI のリッチな WEB フロントエンドを支える技術
nenonaninu
3
1.5k
C# ではじめる OpenTelemetry
nenonaninu
0
4.4k
明日から使える ASP.NET Core ロギング術!
nenonaninu
1
9.2k
C# の async/await は実際にどうやって動いているか
nenonaninu
10
25k
C# と HTTP/2 と gRPC
nenonaninu
3
8.3k
SignalR を使ったアプリケーション開発をより快適に!
nenonaninu
1
2.3k
Other Decks in Technology
See All in Technology
社外コミュニティで学び社内に活かす共に学ぶプロジェクトの実践/backlogworld2024
nishiuma
0
260
10個のフィルタをAXI4-Streamでつなげてみた
marsee101
0
170
あの日俺達が夢見たサーバレスアーキテクチャ/the-serverless-architecture-we-dreamed-of
tomoki10
0
460
スタートアップで取り組んでいるAzureとMicrosoft 365のセキュリティ対策/How to Improve Azure and Microsoft 365 Security at Startup
yuj1osm
0
210
サーバレスアプリ開発者向けアップデートをキャッチアップしてきた #AWSreInvent #regrowth_fuk
drumnistnakano
0
190
AWS re:Invent 2024で発表された コードを書く開発者向け機能について
maruto
0
190
ブラックフライデーで購入したPixel9で、Gemini Nanoを動かしてみた
marchin1989
1
530
20241220_S3 tablesの使い方を検証してみた
handy
4
400
マルチプロダクト開発の現場でAWS Security Hubを1年以上運用して得た教訓
muziyoshiz
3
2.3k
大幅アップデートされたRagas v0.2をキャッチアップ
os1ma
2
530
KubeCon NA 2024 Recap / Running WebAssembly (Wasm) Workloads Side-by-Side with Container Workloads
z63d
1
250
ハイテク休憩
sat
PRO
2
150
Featured
See All Featured
Faster Mobile Websites
deanohume
305
30k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
665
120k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Music & Morning Musume
bryan
46
6.2k
jQuery: Nuts, Bolts and Bling
dougneiner
61
7.5k
How to Think Like a Performance Engineer
csswizardry
22
1.2k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
Visualization
eitanlees
146
15k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
365
25k
Designing Experiences People Love
moore
138
23k
We Have a Design System, Now What?
morganepeng
51
7.3k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
520
Transcript
.NET 8 で既定で有効になった Dynamic PGO について .NET ラボ 2023/10/28 何縫ねの。
自己紹介 1 • 所属: NTTコミュニケーションズ イノベーションセンター • 趣味: C#, OSS,
ドール, 一眼(α7 IV) • 執心領域 • C# ⇔ TypeScript • SignalR 何縫ねの。 nenoNaninu nenoMake ブログ https://blog.neno.dev その他 https://neno.dev
OSS 紹介 2 属性を付与するだけ Tapper • C# の型定義から TypeScript の型定義を生成する
.NET Tool/ library • JSON / MessagePack 対応! https://github.com/nenoNaninu/Tapper
OSS 紹介 3 • C# の SignalR Client を強く型付けするための Source
Generator TypedSignalR.Client Before After (using TypedSignalR.Client) こんな SignalR の Hub と Receiver の interface が あったとして… 脱文字列! 全てが強く型付け! https://github.com/nenoNaninu/TypedSignalR.Client
4 • TypeScript の SignalR Client を強く型付けするための .NET Tool /
library TypedSignalR.Client.TypeScript Before After (using TypedSignalR.Client.TypeScript) 脱文字列! 全てが強く型付け! TypeScript 用の型を C# から自動生成 MessagePack Hub Protocol 対応! https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript 属性を付与するだけ! OSS 紹介
5 • SignalR 使ったアプリを快適に開発するための GUI を自動生成する library • 2 step
で利用可能! • http pipeline に middleware の追加 • Hub と Receiver を定義してる interface に属性を付与 • JWT 認証 サポート • パラメータのユーザ定義型サポート • JSON で入力! SignalR 版 SwaggerUI TypedSignalR.Client.DevTools https://github.com/nenoNaninu/TypedSignalR.Client.DevTools OSS 紹介
.NET 8 リリース直前 6
.NET 8 リリース直前 7 毎 年 恒 例 https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/
.NET 8 リリース直前 8 Σ(゚Д゚) https://github.com/dotnet/runtime/pull/86225 ※ Tiered PGO =
Dynamic PGO
お品書き 9 • 歴史と概観 • Instrumentation • 最適化例 • 注意事項
歴史と概観 10
歴史と概観 11 • .NET Core 2.1 • Tiered compilation が導入。ただし既定では無効。
• .NET Core 3.0 • Tiered compilation が既定で有効 • .NET 6 • Dynamic PGO 導入。ただし既定では無効。 • .NET 7 • On-Stack Replacement (OSR) が導入 • .NET 8 • Dynamic PGO が 既定で有効 歴史
歴史と概観 12 Tiered compilation とは? w/o Tiered compilation IL JIT
https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/tiered-compilation.md Optimized code
歴史と概観 13 Tiered compilation とは? w/o Tiered compilation IL JIT
Optimized code x86 assembly 等 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/tiered-compilation.md
歴史と概観 14 Tiered compilation とは? w/o Tiered compilation w/ Tiered
compilation IL JIT IL JIT Quick JIT Tier0 Unoptimized code Tire1 Optimized code Optimized code x86 assembly 等 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/tiered-compilation.md
歴史と概観 15 Tiered compilation とは? コンパイル速度優先 最適化甘め w/o Tiered compilation
w/ Tiered compilation IL JIT IL JIT Quick JIT Tier0 Unoptimized code Tire1 Optimized code Optimized code x86 assembly 等 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/tiered-compilation.md
歴史と概観 16 Tiered compilation とは? コンパイル速度優先 最適化甘め w/o Tiered compilation
w/ Tiered compilation IL JIT IL JIT Quick JIT Tier0 Unoptimized code Tire1 Optimized code .NET 8 では 最低限度の最適化は されている Optimized code x86 assembly 等 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/tiered-compilation.md
歴史と概観 17 Tiered compilation とは? コンパイル速度優先 最適化甘め w/o Tiered compilation
w/ Tiered compilation IL JIT IL JIT Quick JIT Tier0 Unoptimized code Tire1 Optimized code 高頻度で呼ばれる メソッドは最適化 .NET 8 では 最低限度の最適化は されている Optimized code x86 assembly 等 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/tiered-compilation.md
歴史と概観 18 • 実行中のメソッド (= On-Stack) の code をあるバージョンから 別のバージョンに切り替える(Replacement)の技術。
• e.g., Tire0 code から Tire1 code に切り替える等。 • Backward branch (≒ループ) を含むメソッドで特に嬉しい。 • .NET 6 以前はループを含んでいたら Tire1 直行だった。 • OSRが実装されてない場合、無限ループが永遠に Tire0 で実行されてしまうため。 • .NET 7 以後はループを含んでいても Tire0 で実行された後、 ループ回数が多い場合にのみ Tire1 で実行可能になった。 On-Stack Replacement (OSR) とは? https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/OnStackReplacement.md Dynamic PGO 的に重要 (無限ループをプロファイリング結果をもとに最適化可能)
歴史と概観 19 • PGO : Profile-guided optimization • その名の通り、プロファイリング結果をもとに最適化する。 •
Static PGO 1. アプリケーションコードに計測用のコードを挿入し 2. 主要なシナリオで実行 & 計測し 3. その計測結果をもとに最適化をかけてリビルド • Dynamic PGO • Static PGO がやっていた事を全部実行時に行う • JIT の強み Dynamic PGO とは? https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/DynamicPgo.md Tiering と OSR が導入されたおかげで ここまで出来るように
歴史と概観 20 • RedyToRun (R2R) を使うかどうかで違いが出てくる。 Dynamic PGO の流れ https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/
歴史と概観 21 • 前提 • Tier0 では可能な限り素早く JIT を終わらせたい。 •
一方で最適化は時間がかかる。 • 幾つかの最適化は上記を両立しながら出来る。 • JIT が Tier0 で消費する時間の多くは runtime の VM とのやりとり • 型の解決など • 不要な分岐を大幅に削除できれば Tier 0 でのコンパイルを 高速化しながら、code の品質も向上。 Tier 0 で行われる最適化
歴史と概観 22 • 定数畳み込み • 定数式は (実行時ではなく) コンパイル時に評価 • JIT
intrinsic • If(typeof(T).IsValueType) の分岐が消失する等 Tier 0 で行われる最適化
歴史と概観 23 • 定数畳み込み • 定数式は (実行時ではなく) コンパイル時に評価 • JIT
intrinsic • If(typeof(T).IsValueType) の分岐が消失する等 Tier 0 で行われる最適化 定数畳み込み T が int じゃなかったら消し飛ぶ (.NET 7以前では Tier1 の最適化)
歴史と概観 24 だそうです。 VM って結局なに。 https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/
Instrumentation 25
Instrumentation 26 • Dynamic PGO のためには各メソッドを何回呼んだかなど計測を する必要がある。 • 計測する用のコードを実行時に挿し込む。 •
メソッドはマルチスレッドで同時に呼ばれる可能性がある。 計測の必要性
Instrumentation 27 • Dynamic PGO のためには各メソッドを何回呼んだかなど計測を する必要がある。 • 計測する用のコードを実行時に挿し込む。 •
メソッドはマルチスレッドで同時に呼ばれる可能性がある。 計測の必要性 どうやってスレッドセーフに、正確に、効率的に計測するか?
Instrumentation 28 1. 素朴に count++ (Racy) • .NET 7 以前はこうだった。
• マルチスレッドだと一部のインクリメントが無効になるが、欲しいの は近似なので問題がないと思われていた。 • 結構な誤差が出て間違った最適化がかかってしまう等の問題が出てき ていた。 2. Interlocked.Increment • 正確なカウントは実現できた • ただしコストが非常に重たかった。 3. Scalable Approximate Counting • 賢いカウント方法を導入。 呼び出し回数の計測方法
Scalable Approximate Counting 29 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 30 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 31 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 32 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 𝒅𝒆𝒍𝒕𝒂 ቐ 𝟎𝒃𝟏𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟎𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 2進数リテラル https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 33 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 𝒅𝒆𝒍𝒕𝒂 ቐ 𝟎𝒃𝟏𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟎𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 2進数リテラル 𝒅𝒆𝒍𝒕𝒂 − 𝟏 ቐ 𝟎𝒃𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 34 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 𝒅𝒆𝒍𝒕𝒂 ቐ 𝟎𝒃𝟏𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟎𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 2進数リテラル 𝒅𝒆𝒍𝒕𝒂 − 𝟏 ቐ 𝟎𝒃𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … いい感じに mask になる https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 35 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 𝒅𝒆𝒍𝒕𝒂 ቐ 𝟎𝒃𝟏𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟎𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 32bit の rand と delta-1 の 論理積を取ると… 2進数リテラル 𝒅𝒆𝒍𝒕𝒂 − 𝟏 ቐ 𝟎𝒃𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … いい感じに mask になる https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 36 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 𝒅𝒆𝒍𝒕𝒂 ቐ 𝟎𝒃𝟏𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟎𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 𝒅𝒆𝒍𝒕𝒂 − 𝟏 ቐ 𝟎𝒃𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 32bit の rand と delta-1 の 論理積を取ると… 初回 ½ で true (1bit の mask) この時 delta = 0b10 = 2 いい感じに mask になる 2進数リテラル https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 37 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 𝒅𝒆𝒍𝒕𝒂 ቐ 𝟎𝒃𝟏𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟎𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 𝒅𝒆𝒍𝒕𝒂 − 𝟏 ቐ 𝟎𝒃𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 32bit の rand と delta-1 の 論理積を取ると… 初回 ½ で true (1bit の mask) この時 delta = 0b10 = 2 いい感じに mask になる 2進数リテラル 次に ¼ で true (2bit の mask) この時 delta = 0b100 = 4 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 38 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥
𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 𝒅𝒆𝒍𝒕𝒂 ቐ 𝟎𝒃𝟏𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟎𝟎 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 𝒅𝒆𝒍𝒕𝒂 − 𝟏 ቐ 𝟎𝒃𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟑) 𝟎𝒃𝟏𝟏 (log𝟐 𝒄𝒐𝒖𝒏𝒕 = 𝟏𝟒) … 32bit の rand と delta-1 の 論理積を取ると… 初回 ½ で true (1bit の mask) この時 delta = 0b10 = 2 いい感じに mask になる 2進数リテラル 次に ¼ で true (2bit の mask) この時 delta = 0b100 = 4 最終的に delta が加算 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 39 • X 軸が最終的な試行回数、Y 軸が精度 • CPU
のスレッド数は 12 精度は? https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 40 • X 軸が最終的な試行回数、Y 軸が精度 • CPU
のスレッド数は 12 精度は? Scalable が優秀 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 41 • X 軸が最終的な試行回数、Y 軸が精度 • CPU
のスレッド数は 12 精度は? Scalable が優秀 一方で Racy は 許容できない誤差 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 42 • Racy を取り除いた図。 • Scalable はワーストケースでも
3% のズレで済んでいる。 精度は? https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 43 • X 軸が最終的な試行回数、Y 軸がかかった合計時間 • 217
を超えたあたりから Interlocked が顕著に高コストに。 速度は? https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Scalable Approximate Counting 44 • X 軸が最終的な試行回数、Y 軸がかかった合計時間 • 217
を超えたあたりから Interlocked が顕著に高コストに。 速度は? Scalable と Racy は ほぼ変らない性能 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
Instrumentation 45 • Dynamic PGO では devirtualization 等のために virtual method
/ interface method の呼び出し先の具象型が何で、 それが何回実行されたか…とかが知りたい。 • 最もよく呼ばれる型は devirtualization する。 • しかし、呼び出された具象型を正確にカウントすることは高価。 • なお、PGO 的に知りたいのは割合。正確な回数でない。 呼び出し回数以外の counting
Instrumentation 46 • Dynamic PGO では devirtualization 等のために virtual method
/ interface method の呼び出し先の具象型が何で、 それが何回実行されたか…とかが知りたい。 • 最もよく呼ばれる型は devirtualization する。 • しかし、呼び出された具象型を正確にカウントすることは高価。 • なお、PGO 的に知りたいのは割合。正確な回数でない。 呼び出し回数以外の counting さてどうするか 🤔
Instrumentation 47 • Sampling とは • n 個ある母集団から k 個取り出す操作
• n が既知かつそこそこのサイズまでは簡単 • Dynamic PGO で求められる sampling はちょっと難しい • 未知の n に対応 • 母集団が呼び出しの集合なので、当然 n は未知であり、増加し続ける • 省メモリかつ高速 • 全ての呼び出しを保存とかは当然不適切。 • つまり、過去の呼び出しを遡るとかもできない。 • 一様なサンプリング Sampling して解決。ただし…
Instrumentation 48 • Sampling とは • n 個ある母集団から k 個取り出す操作
• n が既知かつそこそこのサイズまでは簡単 • Dynamic PGO で求められる sampling はちょっと難しい • 未知の n に対応 • 母集団が呼び出しの集合なので、当然 n は未知であり、増加し続ける • 省メモリかつ高速 • 全ての呼び出しを保存とかは当然不適切。 • つまり、過去の呼び出しを遡るとかもできない。 • 一様なサンプリング Sampling して解決。ただし… 要するに終端の分からないストリームから 一様にサンプリングしないといけない
Instrumentation 49 • Reservoir : 貯水池 • サンプリング結果が reservoir に保存される
• ストリームを1方向に舐めながら、 一様にサンプリング可能な素敵アルゴリズム • これが一様サンプリングである証明は いろいろ文献あるのでそちらを参照のこと • なお、こまやかな調整が必要だった模様。 • https://github.com/dotnet/runtime/pull/87332 Reservoir sampling
Instrumentation 50 • Reservoir : 貯水池 • サンプリング結果が reservoir に保存される
• ストリームを1方向に舐めながら、 一様にサンプリング可能な素敵アルゴリズム • これが一様サンプリングである証明は いろいろ文献あるのでそちらを参照のこと • なお、こまやかな調整が必要だった模様。 • https://github.com/dotnet/runtime/pull/87332 Reservoir sampling
Instrumentation 51 • 静的な解析に基づく最適化、いろいろありますよね。 • 分岐予測とか。 • Dynamic PGO は静的な
profile と instrumentation によって得られた profile を合成して最適化を行う。 • profile synthesis とかいう。 Dynamic PGO による最適化は instrumentation にのみ基づくわけではない https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/
最適化例 52
最適化例 53 • Devirtualization • Inlining で、実際どういう最適化されるの? 他にもいろいろあるけど 大きな柱はこの 2
つ
最適化例 54 Devirtualization + Inlining の具体例
最適化例 55 Devirtualization + Inlining の具体例
最適化例 56 どんな最適化が?
最適化例 57 どんな最適化が?
最適化例 58 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO
により devirtualization
最適化例 59 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO
により devirtualization Guarded devirtualization (GDV) と呼ばれる最適化
最適化例 60 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO
により devirtualization Guarded devirtualization (GDV) と呼ばれる最適化
最適化例 61 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO
により devirtualization さらに Inline 化 Guarded devirtualization (GDV) と呼ばれる最適化
最適化例 62 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO
により devirtualization さらに Inline 化 Guarded devirtualization (GDV) と呼ばれる最適化
最適化例 63 x86 assembly を覗いてみると… .NET 7 .NET 8
最適化例 64 x86 assembly を覗いてみると… .NET 7 .NET 8 型のチェックが
挟まっている
最適化例 65 x86 assembly を覗いてみると… .NET 7 .NET 8 型のチェックが
挟まっている 42 が 埋め込ま れている (0x2A は 42)
最適化例 66 • 既定では 1 つ。 • DOTNET_JitGuardedDevirtualizationMaxTypeChecks 環境変数で設定可能。 Guarded
devirtualization される型は幾つまで?
最適化例 67 • 既定では 1 つ。 • DOTNET_JitGuardedDevirtualizationMaxTypeChecks 環境変数で設定可能。 Guarded
devirtualization される型は幾つまで? 必ずしもパフォーマンスが改善するとは 限らないので注意(悪化する場合も)
最適化例 68 • 既定では 1 つ。 • DOTNET_JitGuardedDevirtualizationMaxTypeChecks 環境変数で設定可能。 Guarded
devirtualization される型は幾つまで? Generic host 全盛の昨今では 1 interface 1 class で DI に登録されるので 既定で十分高速化が期待できる 必ずしもパフォーマンスが改善するとは 限らないので注意(悪化する場合も)
最適化例 69 Delegate にも Guarded devirtualization + inlining
最適化例 70 Delegate にも Guarded devirtualization + inlining 常に _func
が 呼び出されているだけ
最適化例 71 Delegate にも Guarded devirtualization + inlining 常に _func
が 呼び出されているだけ 毎回 delegate の invoke は 無駄が大きい
最適化例 72 • GDV + inlining により既知の delegate なら delegate
の invoke を避けるようなコードを生成 Delegate にも Guarded devirtualization + inlining 疑似コード
最適化例 73 • GDV + inlining により既知の delegate なら delegate
の invoke を避けるようなコードを生成 Delegate にも Guarded devirtualization + inlining 疑似コード Delegate の invoke は 避けられた
最適化例 74 • GDV + inlining により既知の delegate なら delegate
の invoke を避けるようなコードを生成 Delegate にも Guarded devirtualization + inlining 疑似コード Delegate の invoke は 避けられた ループの中で 何度も比較は無駄…
最適化例 75 • Hoisting という最適化を行う • ループの中で不変なのであれば、ループの外に出す Delegate にも Guarded
devirtualization + inlining + α 疑似コード 最適化対象の delegate かの 比較はループの外に出せた
最適化例 76 • Hoisting という最適化を行う • ループの中で不変なのであれば、ループの外に出す Delegate にも Guarded
devirtualization + inlining + α 疑似コード 最適化対象の delegate かの 比較はループの外に出せた ループの中で分岐がまだある…
最適化例 77 • Loop cloning という最適化を行う Delegate にも Guarded devirtualization
+ inlining + α 疑似コード
最適化例 78 • Loop cloning という最適化を行う Delegate にも Guarded devirtualization
+ inlining + α 疑似コード 最終的に大幅な 高速化
注意事項 79
注意事項 80 • マイクロベンチマークなどのいくつかのパターンでは、 Dynamic PGO を強く意識する必要がある。 • Dynamic PGO
on/off して双方でベンチマークとるなどの対策が必要。 • なぜ? • マイクロベンチマークで Dynamic PGO が有効になってしまうと、 開発者が書いたコードが原因で高速化が実現できたのか、 Dynamic PGO によって高速化が実現できたのか、分からなくなってしまう。 高速化の原因は Dynamic PGO かも?
注意事項 81 • 開発者が書く際に手動で最適化をしなくて良くなる訳ではない。 • 例えば具象型でいいフィールドを interface にしない、とか。 手動の最適化はいまだ有効 .NET
8 からこれを促す analyzer が入るそうです
まとめ 82 • 歴史と概観 • Tiered compilation • On-Stack Replacement
• Dynamic PGO • Tier 0 での最適化 • Instrumentation • Scalable Approximate Counting • Reservoir sampling • 最適化例 • Guarded Devirtualization • Inlining • 注意事項 • ベンチマークとか取る際には気を付けよう • 手動での最適化は未だ大事