Upgrade to Pro — share decks privately, control downloads, hide ads and more …

.NET 8 で既定で有効になった Dynamic PGO について

neno
October 28, 2023

.NET 8 で既定で有効になった Dynamic PGO について

.NET ラボ 2023/10/28 での発表資料

ブログ
https://blog.neno.dev/entry/2023/10/29/131336

neno

October 28, 2023
Tweet

More Decks by neno

Other Decks in Technology

Transcript

  1. 自己紹介 1 • 所属: NTTコミュニケーションズ イノベーションセンター • 趣味: C#, OSS,

    ドール, 一眼(α7 IV) • 執心領域 • C# ⇔ TypeScript • SignalR 何縫ねの。 nenoNaninu nenoMake ブログ https://blog.neno.dev その他 https://neno.dev
  2. OSS 紹介 2 属性を付与するだけ Tapper • C# の型定義から TypeScript の型定義を生成する

    .NET Tool/ library • JSON / MessagePack 対応! https://github.com/nenoNaninu/Tapper
  3. 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. 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. 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 紹介
  6. 歴史と概観 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 が 既定で有効 歴史
  7. 歴史と概観 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
  8. 歴史と概観 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
  9. 歴史と概観 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
  10. 歴史と概観 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
  11. 歴史と概観 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
  12. 歴史と概観 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
  13. 歴史と概観 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 的に重要 (無限ループをプロファイリング結果をもとに最適化可能)
  14. 歴史と概観 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 が導入されたおかげで ここまで出来るように
  15. 歴史と概観 21 • 前提 • Tier0 では可能な限り素早く JIT を終わらせたい。 •

    一方で最適化は時間がかかる。 • 幾つかの最適化は上記を両立しながら出来る。 • JIT が Tier0 で消費する時間の多くは runtime の VM とのやりとり • 型の解決など • 不要な分岐を大幅に削除できれば Tier 0 でのコンパイルを 高速化しながら、code の品質も向上。 Tier 0 で行われる最適化
  16. 歴史と概観 22 • 定数畳み込み • 定数式は (実行時ではなく) コンパイル時に評価 • JIT

    intrinsic • If(typeof(T).IsValueType) の分岐が消失する等 Tier 0 で行われる最適化
  17. 歴史と概観 23 • 定数畳み込み • 定数式は (実行時ではなく) コンパイル時に評価 • JIT

    intrinsic • If(typeof(T).IsValueType) の分岐が消失する等 Tier 0 で行われる最適化 定数畳み込み T が int じゃなかったら消し飛ぶ (.NET 7以前では Tier1 の最適化)
  18. Instrumentation 27 • Dynamic PGO のためには各メソッドを何回呼んだかなど計測を する必要がある。 • 計測する用のコードを実行時に挿し込む。 •

    メソッドはマルチスレッドで同時に呼ばれる可能性がある。 計測の必要性 どうやってスレッドセーフに、正確に、効率的に計測するか?
  19. Instrumentation 28 1. 素朴に count++ (Racy) • .NET 7 以前はこうだった。

    • マルチスレッドだと一部のインクリメントが無効になるが、欲しいの は近似なので問題がないと思われていた。 • 結構な誤差が出て間違った最適化がかかってしまう等の問題が出てき ていた。 2. Interlocked.Increment • 正確なカウントは実現できた • ただしコストが非常に重たかった。 3. Scalable Approximate Counting • 賢いカウント方法を導入。 呼び出し回数の計測方法
  20. Scalable Approximate Counting 31 log𝟐 𝒄𝒐𝒖𝒏𝒕 (小数点以下切り捨て) log𝟐 𝒄𝒐𝒖𝒏𝒕 ≥

    𝟏𝟑 𝒄𝒐𝒖𝒏𝒕 ≥ 𝟐𝟏𝟑 = 𝟖𝟏𝟗𝟐 https://github.com/dotnet/runtime/blob/v8.0.0-rc.2.23479.6/docs/design/features/ScalableApproximateCounting.md
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. Instrumentation 45 • Dynamic PGO では devirtualization 等のために virtual method

    / interface method の呼び出し先の具象型が何で、 それが何回実行されたか…とかが知りたい。 • 最もよく呼ばれる型は devirtualization する。 • しかし、呼び出された具象型を正確にカウントすることは高価。 • なお、PGO 的に知りたいのは割合。正確な回数でない。 呼び出し回数以外の counting
  35. Instrumentation 46 • Dynamic PGO では devirtualization 等のために virtual method

    / interface method の呼び出し先の具象型が何で、 それが何回実行されたか…とかが知りたい。 • 最もよく呼ばれる型は devirtualization する。 • しかし、呼び出された具象型を正確にカウントすることは高価。 • なお、PGO 的に知りたいのは割合。正確な回数でない。 呼び出し回数以外の counting さてどうするか 🤔
  36. Instrumentation 47 • Sampling とは • n 個ある母集団から k 個取り出す操作

    • n が既知かつそこそこのサイズまでは簡単 • Dynamic PGO で求められる sampling はちょっと難しい • 未知の n に対応 • 母集団が呼び出しの集合なので、当然 n は未知であり、増加し続ける • 省メモリかつ高速 • 全ての呼び出しを保存とかは当然不適切。 • つまり、過去の呼び出しを遡るとかもできない。 • 一様なサンプリング Sampling して解決。ただし…
  37. Instrumentation 48 • Sampling とは • n 個ある母集団から k 個取り出す操作

    • n が既知かつそこそこのサイズまでは簡単 • Dynamic PGO で求められる sampling はちょっと難しい • 未知の n に対応 • 母集団が呼び出しの集合なので、当然 n は未知であり、増加し続ける • 省メモリかつ高速 • 全ての呼び出しを保存とかは当然不適切。 • つまり、過去の呼び出しを遡るとかもできない。 • 一様なサンプリング Sampling して解決。ただし… 要するに終端の分からないストリームから 一様にサンプリングしないといけない
  38. Instrumentation 49 • Reservoir : 貯水池 • サンプリング結果が reservoir に保存される

    • ストリームを1方向に舐めながら、 一様にサンプリング可能な素敵アルゴリズム • これが一様サンプリングである証明は いろいろ文献あるのでそちらを参照のこと • なお、こまやかな調整が必要だった模様。 • https://github.com/dotnet/runtime/pull/87332 Reservoir sampling
  39. Instrumentation 50 • Reservoir : 貯水池 • サンプリング結果が reservoir に保存される

    • ストリームを1方向に舐めながら、 一様にサンプリング可能な素敵アルゴリズム • これが一様サンプリングである証明は いろいろ文献あるのでそちらを参照のこと • なお、こまやかな調整が必要だった模様。 • https://github.com/dotnet/runtime/pull/87332 Reservoir sampling
  40. Instrumentation 51 • 静的な解析に基づく最適化、いろいろありますよね。 • 分岐予測とか。 • Dynamic PGO は静的な

    profile と instrumentation によって得られた profile を合成して最適化を行う。 • profile synthesis とかいう。 Dynamic PGO による最適化は instrumentation にのみ基づくわけではない https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/
  41. 最適化例 59 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO

    により devirtualization Guarded devirtualization (GDV) と呼ばれる最適化
  42. 最適化例 60 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO

    により devirtualization Guarded devirtualization (GDV) と呼ばれる最適化
  43. 最適化例 61 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO

    により devirtualization さらに Inline 化 Guarded devirtualization (GDV) と呼ばれる最適化
  44. 最適化例 62 どんな最適化が? PGO が無ければ普通に interface の dispatch. Dynamic PGO

    により devirtualization さらに Inline 化 Guarded devirtualization (GDV) と呼ばれる最適化
  45. 最適化例 65 x86 assembly を覗いてみると… .NET 7 .NET 8 型のチェックが

    挟まっている 42 が 埋め込ま れている (0x2A は 42)
  46. 最適化例 67 • 既定では 1 つ。 • DOTNET_JitGuardedDevirtualizationMaxTypeChecks 環境変数で設定可能。 Guarded

    devirtualization される型は幾つまで? 必ずしもパフォーマンスが改善するとは 限らないので注意(悪化する場合も)
  47. 最適化例 68 • 既定では 1 つ。 • DOTNET_JitGuardedDevirtualizationMaxTypeChecks 環境変数で設定可能。 Guarded

    devirtualization される型は幾つまで? Generic host 全盛の昨今では 1 interface 1 class で DI に登録されるので 既定で十分高速化が期待できる 必ずしもパフォーマンスが改善するとは 限らないので注意(悪化する場合も)
  48. 最適化例 71 Delegate にも Guarded devirtualization + inlining 常に _func

    が 呼び出されているだけ 毎回 delegate の invoke は 無駄が大きい
  49. 最適化例 72 • GDV + inlining により既知の delegate なら delegate

    の invoke を避けるようなコードを生成 Delegate にも Guarded devirtualization + inlining 疑似コード
  50. 最適化例 73 • GDV + inlining により既知の delegate なら delegate

    の invoke を避けるようなコードを生成 Delegate にも Guarded devirtualization + inlining 疑似コード Delegate の invoke は 避けられた
  51. 最適化例 74 • GDV + inlining により既知の delegate なら delegate

    の invoke を避けるようなコードを生成 Delegate にも Guarded devirtualization + inlining 疑似コード Delegate の invoke は 避けられた ループの中で 何度も比較は無駄…
  52. 最適化例 75 • Hoisting という最適化を行う • ループの中で不変なのであれば、ループの外に出す Delegate にも Guarded

    devirtualization + inlining + α 疑似コード 最適化対象の delegate かの 比較はループの外に出せた
  53. 最適化例 76 • Hoisting という最適化を行う • ループの中で不変なのであれば、ループの外に出す Delegate にも Guarded

    devirtualization + inlining + α 疑似コード 最適化対象の delegate かの 比較はループの外に出せた ループの中で分岐がまだある…
  54. 注意事項 80 • マイクロベンチマークなどのいくつかのパターンでは、 Dynamic PGO を強く意識する必要がある。 • Dynamic PGO

    on/off して双方でベンチマークとるなどの対策が必要。 • なぜ? • マイクロベンチマークで Dynamic PGO が有効になってしまうと、 開発者が書いたコードが原因で高速化が実現できたのか、 Dynamic PGO によって高速化が実現できたのか、分からなくなってしまう。 高速化の原因は Dynamic PGO かも?
  55. まとめ 82 • 歴史と概観 • Tiered compilation • On-Stack Replacement

    • Dynamic PGO • Tier 0 での最適化 • Instrumentation • Scalable Approximate Counting • Reservoir sampling • 最適化例 • Guarded Devirtualization • Inlining • 注意事項 • ベンチマークとか取る際には気を付けよう • 手動での最適化は未だ大事