Go Wiki: CustomPprofProfiles
元々はhttps://rakyll.org/custom-profiles/で公開されました。
Goは、Goプログラムからプロファイリングデータを収集するために、すぐに使用できるいくつかのpprofプロファイルを提供しています。
runtime/pprofパッケージによって提供される組み込みプロファイル
- profile: CPUプロファイルは、プログラムが(スリープまたはI/O待ちではなく)アクティブにCPUサイクルを消費している間にどこで時間を費やしているかを判断します。
- heap: ヒーププロファイルは、現在ライブの割り当てを報告します。現在のメモリ使用量を監視したり、メモリリークをチェックするために使用されます。
- threadcreate: スレッド作成プロファイルは、新しいOSスレッドの作成につながるプログラムのセクションを報告します。
- goroutine: ゴルーチンプロファイルは、現在のすべてのゴルーチンのスタックトレースを報告します。
- block: ブロックプロファイルは、ゴルーチンが(タイマーチャネルを含む)同期プリミティブを待機してブロックされている場所を示します。ブロックプロファイルはデフォルトでは有効になっていません。有効にするには、runtime.SetBlockProfileRateを使用してください。
- mutex: Mutexプロファイルは、ロック競合を報告します。Mutexの競合によりCPUが完全に利用されていないと思われる場合は、このプロファイルを使用してください。Mutexプロファイルはデフォルトでは有効になっていません。有効にするにはruntime.SetMutexProfileFractionを参照してください。
組み込みプロファイルに加えて、runtime/pprofパッケージを使用すると、カスタムプロファイルをエクスポートし、このプロファイルに寄与する実行スタックを記録するようにコードをインストルメント化できます。
Blobサーバーがあり、それ用のGoクライアントを作成していると想像してください。そして、ユーザーがクライアントで開かれたBlobをプロファイリングできるようにしたいとします。プロファイルを作成し、Blobのオープンとクローズのイベントを記録できるため、ユーザーは任意の時点で開いているBlobの数を知ることができます。
これは、いくつかのBlobを開くことができるblobstoreパッケージです。新しいカスタムプロファイルを作成し、Blobのオープンに寄与する実行スタックの記録を開始します。
package blobstore
import "runtime/pprof"
var openBlobProfile = pprof.NewProfile("blobstore.Open")
// Open opens a blob, all opened blobs need
// to be closed when no longer in use.
func Open(name string) (*Blob, error) {
blob := &Blob{name: name}
// TODO: Initialize the blob...
openBlobProfile.Add(blob, 2) // add the current execution stack to the profile
return blob, nil
}
そして、ユーザーがBlobを閉じたい場合は、現在のBlobに関連付けられた実行スタックをプロファイルから削除する必要があります。
// Close closes the blob and frees the
// underlying resources.
func (b *Blob) Close() error {
// TODO: Free other resources.
openBlobProfile.Remove(b)
return nil
}
そして今、このパッケージを使用するプログラムから、blobstore.Open
プロファイルデータを取得し、日常のpprofツールを使用して調べ、視覚化できるようになるはずです。
いくつかのBlobを開く小さなメインプログラムを書いてみましょう。
package main
import (
"fmt"
"math/rand"
"net/http"
_ "net/http/pprof" // as a side effect, registers the pprof endpoints.
"time"
"myproject.org/blobstore"
)
func main() {
for i := 0; i < 1000; i++ {
name := fmt.Sprintf("task-blob-%d", i)
go func() {
b, err := blobstore.Open(name)
if err != nil {
// TODO: Handle error.
}
defer b.Close()
// TODO: Perform some work, write to the blob.
}()
}
http.ListenAndServe("localhost:8888", nil)
}
サーバーを起動し、次にgo toolを使用してプロファイルデータを読み取り、視覚化します。
$ go tool pprof http://localhost:8888/debug/pprof/blobstore.Open
(pprof) top
Showing nodes accounting for 800, 100% of 800 total
flat flat% sum% cum cum%
800 100% 100% 800 100% main.main.func1 /Users/jbd/src/hello/main.go
800個の開いているBlobがあり、すべてのオープンがmain.main.func1から来ていることがわかります。この小さな例では、それ以上何も見ることはありませんが、複雑なサーバーでは、開いているBlobで動作する最もホットなスポットを調べて、ボトルネックやリークを見つけることができます。
このコンテンツはGo Wikiの一部です。