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
PGOによるコンパイラ最適化 / Compiler Optimization with PGO
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Koya IWAMURA
March 07, 2023
Programming
1k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
PGOによるコンパイラ最適化 / Compiler Optimization with PGO
Koya IWAMURA
March 07, 2023
More Decks by Koya IWAMURA
See All by Koya IWAMURA
What's new in Go 1.26?
ciarana
2
420
What's new in Go 1.25?
ciarana
1
110
What's new in Go 1.24?
ciarana
1
270
What's new in Go 1.21?
ciarana
2
1.7k
Go1.13以後のエラーハンドリングについて語ろう / Let's talk about error handling after Go 1 13
ciarana
10
8.8k
Other Decks in Programming
See All in Programming
Oxcを導入して開発体験が向上した話
yug1224
4
300
Swiftのレキシカルスコープ管理
kntkymt
0
220
AI 時代のソフトウェア設計の学び方
masuda220
PRO
29
12k
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
200
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
490
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
240
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
230
JavaDoc 再入門
nagise
0
320
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
210
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
20
6.4k
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.2k
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
Featured
See All Featured
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.4k
[SF Ruby Conf 2025] Rails X
palkan
2
1.1k
Building a Scalable Design System with Sketch
lauravandoore
463
34k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.1k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
400
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.3k
Become a Pro
speakerdeck
PRO
31
6k
Mobile First: as difficult as doing things right
swwweet
225
10k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
140
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Transcript
PGOによる コンパイラ最適化 シアラナ Go 1.20 Release Party 2023-02-21
自己紹介 • シアラナ ◦ Twitter: cia_rana / Zenn: koya_iwamura •
株式会社アプリボット ◦ 新規ゲームプロジェクトでサーバーサイドエンジニア • Goの記事書いたり、コントリビュートしたり
目次 • 通常のコンパイラ最適化とPGOによるコンパイラ最適化 • PGOの使用例 & ベンチマーク • PGO FAQ
• PGOの今後
通常のコンパイラ最適化 • インライン展開 ◦ 関数の呼び出し元に関数の呼び出し先を展開する • エスケープ解析 ◦ 変数の値をヒープに退避しなくて良いか判定する •
devirtualization ◦ interfaceのメソッド呼び出しを具象型のメソッド呼び出しに変換する • SSA最適化 ◦ SSA: ASTからマシンコードに変換するまでの間の中間コード ◦ $ go tool compile -d ssa/help で詳細が見れます
通常のコンパイラ最適化 • 一見さまざまな最適化が施されているように見える... • ただ、これはあくまでも動作させる前のコードを静的解析し、 決められたルールに従って最適化を行っているに過ぎない
PGOによるコンパイラ最適化 • PGO: Profile-Guided Optimization • ランタイム時のCPUやRAMの利用状況、関数呼び出しの頻度などを収集し、 次回のコンパイラ最適化にフィードバックする • 実際のワークロードにより特化したコンパイラ最適化を行える
• いわば「推測するな、計測せよ」に則った最適化手法
Go 1.20 で導入された PGO • 2~4%の実行速度高速化が見込めるらしい • 今回入ったのはインライン最適化のみ ◦ その他の最適化については最後の方で
• PGO で使用するプロファイルはpprofのプロファイル結果を用いる ◦ pprofのプロファイル結果には PGOに必要な情報が含まれていなかったり、 PGOに不必要な 情報が多くファイルサイズが大きくなる傾向があり、今後別の形式が導入される可能性が あることが示唆されている(確度はまだ低い) ◦ 別の形式が定義される場合は pprofのプロファイル結果から変換するツールを提供する とのこと ◦ https://github.com/golang/go/issues/55022#issuecomment-1244259222 • 今回のリリースではまだパブリックプレビュー版なので、本番環境での利用は避け る
PGO 使用例 & ベンチマーク
実行環境 • OS: macOS Monterey • CPU: Intel Core i9,
8core, 2.4GHz • RAM: 32GB • Go: 1.20.0
使用するコード • GopherCon 2019で行われた「High Performance Go Workshop」の mandelwebを用いて、ベンチマークを取ってみる • mandelwebはマンデルブロ集合を生成するWebサーバー
https://dave.cheney.net/high-performance-go-workshop/dotgo-paris.html
1. プロファイルを取る手段を選択する プロファイルの取り方は大きく分けて3つ • github.com/pkg/profile パッケージを用いる • net/http/pprof パッケージを用いる •
ベンチマークで取得する
1. プロファイルを取る手段を選択する プロファイルの取り方は大きく分けて3つ • github.com/pkg/profile パッケージを用いる • net/http/pprof パッケージを用いる •
ベンチマークで取得する
2. PGOを無効にしてビルドする 現在のディレクトリ構成 $ tree ├── cmd │ └── mandelweb
│ ├── benchmark_test.go │ └── main.go └── go.mod
2. PGOを無効にしてビルドする $ go build -pgo=off -o mandelweb_nopgo ./cmd/mandelweb/ •
Go 1.20から追加されたビルドフラグ • offに設定することでプロファイルを明示的に使わない設定にできる
2. PGOを無効にしてビルドする $ ./mandelweb_nopgo • PGOを無効にしてビルドした Webサーバ • ポート8080で待機中 •
エンドポイント /mandelbrot でマンデルブロ集合を描画して返す
3. ベンチマークを取る(PGO無効) Webサーバーが起動しているターミナルとは別ターミナルでベンチマークを取る $ go test -bench=. -count=30 ./cmd/mandelweb/benchmark_test.go >
benchmark_nopgo.txt • PGOを無効にしてビルドした Webサーバーに対してリクエストを 送るベンチマーク func Benchmark(b *testing.B) { for i := 0; i < b.N; i++ { resp, err := http.Get("http://127.0.0.1:8080/mandelbrot") if err != nil { b.Fatal(err.Error()) } resp.Body.Close() } }
4. プロファイルを取る Apache Bench で負荷をかける $ ab -n 1000 -c
10 http://127.0.0.1:8080/mandelbrot • -n: 最大リクエスト数 • -c: 同時リクエスト数 • つまり10並列で合計1000回リクエストする
4. プロファイルを取る 負荷がかかっている間にプロファイルを取る $ curl -o cmd/mandelweb/default.pgo http://127.0.0.1:8080/debug/pprof/profile?seconds=10 • 保存するファイル名
• main パッケージと同じディレ クトリに保存する • 10秒間プロファイルを取る • 内部で net/http/pprof が 使用されている
4. プロファイルを取る 現在のディレクトリ構成 $ tree ├── benchmark_nopgo.txt ├── cmd │
└── mandelweb │ ├── benchmark_test.go │ ├── default.pgo │ └── main.go ├── go.mod └── mandelweb_nopgo
5. PGOを有効にしてビルドする $ go build -pgo=auto -o mandelweb_pgo ./cmd/mandelweb/ •
無効時はoffを設定していたが、有効時は autoを設定する • autoにするとmainパッケージのdefault.pgoを探索して使用する • -pgo=./cmd/mandelweb/default.pgo のようにファイルパスを 指定することもできる • Go 1.20ではデフォルトでoffだが、将来的にデフォルトで autoに なることが示唆されている
5. PGOを有効にしてビルドする $ ./mandelweb_pgo • PGOを有効にしてビルドした Webサーバを起動 • 挙動はPGOを無効にしてビルドした mandelweb_nopgoと同じ
6. ベンチマークを取る(PGO有効) Webサーバーを起動しているターミナルとは別ターミナルでベンチマークを取る $ go test -bench=. -count=30 ./cmd/mandelweb/benchmark_test.go >
benchmark_pgo.txt • PGOを有効にしてビルドした Webサーバーに対してリクエストを 送るベンチマーク • ベンチマーカーの中身自体は PGOを 無効にしていたときと同じ
7. ベンチマーク結果を比較する PGOを無効・有効にしたWebサーバーに対しそれぞれベンチマークを 行なった結果を benchstat で比較する $ benchstat benchmark_nopgo.txt benchmark_pgo.txt
• go install golang.org/x/perf/cmd/benchstat@latest でインストール
7. ベンチマーク結果を比較する PGOを有効にすると逆に実行時間が増えてしまった😇 benchmark_nopgo.txt benchmark_pgo.txt vs 41.62 msec/op ± 2%
42.63 msec/op ± 1% +2.41% (p=0.000 n=30)
7. ベンチマーク結果を比較する コンパイラ最適化結果を比較してみる $ go build -pgo=off -o mandelbrot_nopgo -gcflags="-m"
./cmd/mandelweb/ 2> opt_nopgo.txt $ go build -pgo=auto -o mandelbrot_pgo -gcflags="-m" ./cmd/mandelweb/ 2> opt_pgo.txt • ビルド時に-gcflagsに-mをつけると、 最適化結果を出力してくれる
7. ベンチマーク結果を比較する コンパイラ最適化結果を比較してみる $ diff opt_nopgo.txt opt_pgo.txt > cmd/mandelweb/main.go:59:15: inlining
call to fillPixel func fillPixel(m *Img, x, y int) { const n = 1000 const Limit = 2.0 const Zoom = 4 Zr, Zi, Tr, Ti := 0.0, 0.0, 0.0, 0.0 Cr := Zoom*float64(x)/float64(n) - 1.5 Ci := Zoom*float64(y)/float64(n) - 1.0 for i := 0; i < n && (Tr+Ti <= Limit*Limit); i++ { Zi = 2*Zr*Zi + Ci Zr = Tr - Ti + Cr Tr = Zr * Zr Ti = Zi * Zi } paint(&m.m[x][y], Tr, Ti) }
8. ベンチマーク結果の考察 なぜパフォーマンスが落ちたのか?(予想) • pprofでプロファイルを取得した時のワークロードとベンチマークコードが 違うから • インライン展開は特に処理サイズ小さく頻繁に呼び出される関数に対しては有効に 働くが、fillPixelはサイズが大きく、CPUの命令キャッシュや レジスタを圧迫している可能性があるから
• mandelwebの他にも3つほどベンチマークケースを作ったが、 どれもパフォーマンスが改善しなかったので、実行環境由来の可能性もある • パブリックプレビュー版なので、まだ完璧に機能するわけではない
PGO FAQ
PGOによる最適化が行われるのはユーザーコードだけか? • ユーザーコードはもちろん、標準パッケージや3rd partyのパッケージに 対してもコンパイラ最適化は行われる
異なる GOARCH/GOOS のプロファイル結果を利用できるか? • プロファイルの形式はCPUアーキテクチャなどによらないため、 基本的には利用できる • そのため、プロファイル結果をmainパッケージのディレクトリに配置して リポジトリにコミットすることが推奨されている •
ただし、ビルドタグによってビルドされるファイルが異なるとホットな部分が見逃され る場合がある
単一バイナリで複数ワークロードを扱う場合は? 次の3つの解決方法が提示されているがトレードオフがあるので、 メリデメを考えて採用する 1. バイナリを単一ではなくワークロードごとに分ける ◦ それぞれのワークロードに対し最高のフォーマンス改善を期待できるが、 複数バイナリを管理する煩雑さはある 2. パフォーマンスを最も重視するワークロードに対してPGOを適用する
◦ そのワークロードについては最高のパフォーマンス改善を期待できるが、 その他のワークロードのパフォーマンスはそこそこの改善に止まる 3. 複数ワークロードのプロファイル結果をマージする ◦ 2つの目の解決方法のその他のワークロードに比べると、 パフォーマンスの改善を期待できるが、最高のパフォーマンスは期待できない ◦ プロファイルのマージは $ go tool pprof -proto a.pprof b.pprof > c.pprof で行える
ビルド時間は長くならないか? • PGOを有効にしない場合に比べて伸びる • 2回目以降のビルドで同じプロファイルを使用する場合は、 ビルドキャッシュが作られるためビルド時間は抑えられる • プロファイルが大きいと解析するのに時間がかかる問題がある ◦ https://github.com/golang/go/issues/58102
PGOはどのように運用するの? • Go PGOはAutoFDOというフローに基づくように設計されている 1. PGOを無効にしてビルドしたバイナリをプロダクションにリリース 2. プロダクションからプロファイルを収集 3. 次回リリース時にPGOを有効にして収集したプロファイルを用いてビルド
&リリース 4. 2. 3. を繰り返す • AutoFDOは単純だが、注意すべき点とそれを防ぐ考えがある ◦ ソース安定性(Source stability) ◦ 反復安定性(Iterative stability)
ソース安定性 • 一般的にリリース後にはソースは改変されるため、プロファイルを取ったソースと次にビル ドするときのソースは違う • ソースが改変されてもプロファイルをなるべく活用できるように最善を尽くすことが ソース安 定性 • ソース安定性が崩れない条件
◦ ホットな関数外への改変 ◦ 同じパッケージの違うファイルへホットな関数を移動 • ソース安定性が崩れる条件 ◦ ホットな関数の改変 ◦ 関数名の改変 ◦ 違うパッケージへホットな関数を移動
反復安定性 • PGOによってホットとみなされ最適化された関数は、次のビルドではホットではなく なっているはずなので最適化が行われない • そして最適化が行われていない関数が、その次のビルド時に再度ホットをみなされ る • つまり、ある関数がPGOを用いてビルドを行うたびに、最適化が行われた状態と行 われていない状態を繰り返す可能性がある
• Goはこの反復を行わないように保守的にPGOを活用している • このことを反復安定性と呼ぶ
今後予定されている最適化項目 • slice/mapのcapサイズを事前に決める • devirtualization • 実行バイナリ内での関数の配置順序を変える • 寿命の近い値を近い場所にメモリ割り当てする •
レジスタ割り当ての効率化 • など https://github.com/golang/go/issues/55022#issuecomment-1245605666
もっと詳しく知りたい人向け • Proposal: profile-guided optimization ◦ ベースとなるProposal ◦ https://go.googlesource.com/proposal/+/master/design/55022-pgo.md •
Proposal: Design and Implementation of Profile-Guided Optimization (PGO) for Go ◦ 実装方針を説明した Proposal ◦ https://go.googlesource.com/proposal/+/master/design/55022-pgo-implementation.md • PGOの初期実装 ◦ https://go-review.googlesource.com/c/go/+/429863 • PGOの課題の中でGo 1.21で解決予定のリスト ◦ https://github.com/golang/go/issues/55022#issuecomment-1409183967