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

PGOによるコンパイラ最適化 / Compiler Optimization with PGO

PGOによるコンパイラ最適化 / Compiler Optimization with PGO

Koya IWAMURA

March 07, 2023
Tweet

More Decks by Koya IWAMURA

Other Decks in Programming

Transcript

  1. 自己紹介 • シアラナ ◦ Twitter: cia_rana / Zenn: koya_iwamura •

    株式会社アプリボット ◦ 新規ゲームプロジェクトでサーバーサイドエンジニア • Goの記事書いたり、コントリビュートしたり
  2. 通常のコンパイラ最適化 • インライン展開 ◦ 関数の呼び出し元に関数の呼び出し先を展開する • エスケープ解析 ◦ 変数の値をヒープに退避しなくて良いか判定する •

    devirtualization ◦ interfaceのメソッド呼び出しを具象型のメソッド呼び出しに変換する • SSA最適化 ◦ SSA: ASTからマシンコードに変換するまでの間の中間コード ◦ $ go tool compile -d ssa/help で詳細が見れます
  3. Go 1.20 で導入された PGO • 2~4%の実行速度高速化が見込めるらしい • 今回入ったのはインライン最適化のみ ◦ その他の最適化については最後の方で

    • PGO で使用するプロファイルはpprofのプロファイル結果を用いる ◦ pprofのプロファイル結果には PGOに必要な情報が含まれていなかったり、 PGOに不必要な 情報が多くファイルサイズが大きくなる傾向があり、今後別の形式が導入される可能性が あることが示唆されている(確度はまだ低い) ◦ 別の形式が定義される場合は pprofのプロファイル結果から変換するツールを提供する とのこと ◦ https://github.com/golang/go/issues/55022#issuecomment-1244259222 • 今回のリリースではまだパブリックプレビュー版なので、本番環境での利用は避け る
  4. 実行環境 • OS: macOS Monterey • CPU: Intel Core i9,

    8core, 2.4GHz • RAM: 32GB • Go: 1.20.0
  5. 2. PGOを無効にしてビルドする $ go build -pgo=off -o mandelweb_nopgo ./cmd/mandelweb/ •

    Go 1.20から追加されたビルドフラグ • offに設定することでプロファイルを明示的に使わない設定にできる
  6. 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() } }
  7. 4. プロファイルを取る Apache Bench で負荷をかける $ ab -n 1000 -c

    10 http://127.0.0.1:8080/mandelbrot • -n: 最大リクエスト数 • -c: 同時リクエスト数 • つまり10並列で合計1000回リクエストする
  8. 4. プロファイルを取る 負荷がかかっている間にプロファイルを取る $ curl -o cmd/mandelweb/default.pgo http://127.0.0.1:8080/debug/pprof/profile?seconds=10 • 保存するファイル名

    • main パッケージと同じディレ クトリに保存する • 10秒間プロファイルを取る • 内部で net/http/pprof が 使用されている
  9. 4. プロファイルを取る 現在のディレクトリ構成 $ tree ├── benchmark_nopgo.txt ├── cmd │

    └── mandelweb │ ├── benchmark_test.go │ ├── default.pgo │ └── main.go ├── go.mod └── mandelweb_nopgo
  10. 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に なることが示唆されている
  11. 6. ベンチマークを取る(PGO有効) Webサーバーを起動しているターミナルとは別ターミナルでベンチマークを取る $ go test -bench=. -count=30 ./cmd/mandelweb/benchmark_test.go >

    benchmark_pgo.txt • PGOを有効にしてビルドした Webサーバーに対してリクエストを 送るベンチマーク • ベンチマーカーの中身自体は PGOを 無効にしていたときと同じ
  12. 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をつけると、 最適化結果を出力してくれる
  13. 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) }
  14. 単一バイナリで複数ワークロードを扱う場合は? 次の3つの解決方法が提示されているがトレードオフがあるので、 メリデメを考えて採用する 1. バイナリを単一ではなくワークロードごとに分ける ◦ それぞれのワークロードに対し最高のフォーマンス改善を期待できるが、 複数バイナリを管理する煩雑さはある 2. パフォーマンスを最も重視するワークロードに対してPGOを適用する

    ◦ そのワークロードについては最高のパフォーマンス改善を期待できるが、 その他のワークロードのパフォーマンスはそこそこの改善に止まる 3. 複数ワークロードのプロファイル結果をマージする ◦ 2つの目の解決方法のその他のワークロードに比べると、 パフォーマンスの改善を期待できるが、最高のパフォーマンスは期待できない ◦ プロファイルのマージは $ go tool pprof -proto a.pprof b.pprof > c.pprof で行える
  15. ソース安定性 • 一般的にリリース後にはソースは改変されるため、プロファイルを取ったソースと次にビル ドするときのソースは違う • ソースが改変されてもプロファイルをなるべく活用できるように最善を尽くすことが ソース安 定性 • ソース安定性が崩れない条件

    ◦ ホットな関数外への改変 ◦ 同じパッケージの違うファイルへホットな関数を移動 • ソース安定性が崩れる条件 ◦ ホットな関数の改変 ◦ 関数名の改変 ◦ 違うパッケージへホットな関数を移動
  16. もっと詳しく知りたい人向け • 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