こんにちは 私の名前はマルコです。 私はBadooのシステムプログラマです。 Go 1.9の新機能に関するrakyllのすばらしい投稿の翻訳を紹介します。 ラベルはGoプログラムのプロファイリングに非常に役立つと思われます。 たとえば、Badooでは、Cプログラムのコードにタグを付けるために同様のものを使用します。タイマーがトリガーされ、スタックトレースがログに表示される場合、それに加えて、そのようなタグを表示します。 たとえば、特定のUIDを持つユーザーの写真を処理したと言えます。 これは非常に便利であり、Goでも同様の機会が得られたことを非常に嬉しく思います。
プロファイラーラベルはGo 1.9で登場しました。CPUプロファイラーが作成するサンプルにキーと値のペアを追加する機能です。 プロファイラーは、プロセッサーが最も時間を費やす最もホットな機能に関する情報を収集して表示します。 従来のCPUプロファイラーの出力は、関数の名前、ソースファイルの名前、このファイルの行番号などで構成されます。 このデータから、コードのどの部分がこれらのホット関数を呼び出したかを理解することもできます。 出力をフィルタリングして、特定の実行ブランチのより深い概念を取得することもできます。
完全な呼び出しスタックに関する情報は非常に役立ちますが、これはパフォーマンスの問題を見つけるのに必ずしも十分ではありません。 多数のGoプログラマーがGoを使用してサーバーを記述しますが、サーバーのパフォーマンスの問題がどこにあるかを理解することはさらに困難です。 ある実行ブランチを別の実行ブランチから分離することは困難です。または、1つの実行ブランチのみが問題を引き起こす場合(一部のユーザーまたは特定のハンドラー)を理解することは困難です。 Go 1.9からは、現時点で何が起こっているかのコンテキストに関する追加情報を追加し、この情報をプロファイラーで使用して、より孤立したデータを取得する機会があります。
ラベルは多くの場合に役立ちます。 最も明らかなものを次に示します。
- プログラムからの抽象化をプロファイリングプロセスに流したくないのですが、オブジェクトに関するデータはそこで役立ちます。 たとえば、Webサーバーの場合、プロファイラーで裸の関数名ではなくURLを表示する方がはるかに便利です。
- スタックトレースは、作業の開始者が誰であるかを理解するには不十分です。 たとえば、キューハンドラは、誰かが以前に作成したイベントを処理します。 ハンドラーは、この誰かの名前で作品にマークを付けることができます。
- パフォーマンスの問題を見つけるには、処理コンテキストが重要です。
ラベルを追加する
runtime/pprof
はruntime/pprof
ラベルを追加するためのいくつかの新機能がruntime/pprof
ます。 ほとんどのユーザーは、コンテキストを取得してラベルを追加し、新しいコンテキストをf
関数に渡すDo
関数を使用します。
func Do(ctx context.Context, labels LabelSet, f func(context.Context))
現在のゴルーチン内でのみラベルセットを記録します。 fで新しいゴルーチンを作成する場合、引数としてコンテキストを渡すことができます。
labels := pprof.Labels("worker", "purge") pprof.Do(ctx, labels, func(ctx context.Context) { // - ... go update(ctx) // })
上記の作業には、 worker:purge
ラベルが付けられます。
プロファイラーの出力を確認します
このセクションでは、ラベル付きプロファイラーの使用方法を示します。 興味のあるコードをすべてラベルでマークしたら、コードをプロファイリングしてプロファイラーの出力を確認します。
この例では、 net/http/pprof
を使用しnet/http/pprof
。 詳細については、 Goプログラムのプロファイリングの記事を参照してください。
package main import _ "net/http/pprof" func main() { // ... log.Fatal(http.ListenAndServe("localhost:5555", nil)) }
CPUの使用に関するデータを収集します...
$ go tool pprof http://localhost:5555/debug/pprof/profile
ユーティリティがインタラクティブモードになった後、 tags
コマンドを使用して、記録されたすべてのラベルを表示できます。 Go標準ライブラリではラベルと呼ばれていますが、pprofユーティリティはタグに名前を付けることに注意してください。
(pprof) tags http-path: Total 80 70 (87.50%): /messages 10 (12.50%): /user worker: Total 158 158 ( 100%): purge
ご覧のとおり、2つのキー( http-path
、 worker
)とそれぞれにいくつかの値があります。 http-pathキーはHTTPハンドラーを指し、worker:purgeは上記の例のコードを指します。
ラベルでフィルタリングすると、たとえば/user
ハンドラーからのコードのみに焦点を合わせることができます。
(pprof) tagfocus="http-path:/user" (pprof) top10 -cum Showing nodes accounting for 0.10s, 3.05% of 3.28s total flat flat% sum% cum cum% 0 0% 0% 0.10s 3.05% main.generateID.func1 /Users/jbd/src/hello/main.go 0.01s 0.3% 0.3% 0.08s 2.44% runtime.concatstring2 /Users/jbd/go/src/runtime/string.go 0.06s 1.83% 2.13% 0.07s 2.13% runtime.concatstrings /Users/jbd/go/src/runtime/string.go 0.01s 0.3% 2.44% 0.02s 0.61% runtime.mallocgc /Users/jbd/go/src/runtime/malloc.go 0 0% 2.44% 0.02s 0.61% runtime.slicebytetostring /Users/jbd/go/src/runtime/string.go 0 0% 2.44% 0.02s 0.61% strconv.FormatInt /Users/jbd/go/src/strconv/itoa.go 0 0% 2.44% 0.02s 0.61% strconv.Itoa /Users/jbd/go/src/strconv/itoa.go 0 0% 2.44% 0.02s 0.61% strconv.formatBits /Users/jbd/go/src/strconv/itoa.go 0.01s 0.3% 2.74% 0.01s 0.3% runtime.memmove /Users/jbd/go/src/runtime/memmove_amd64.s 0.01s 0.3% 3.05% 0.01s 0.3% runtime.nextFreeFast /Users/jbd/go/src/runtime/malloc.go
この出力には、 http-path:/user
ラベルでマークされたサンプルのみが含まれhttp-path:/user
。 そしてこの結論では、最もロードされた場所/ユーザーハンドラがどこにあるかを簡単に理解できます。
追加のフィルタリングのためにtagshow
、 taghide
およびtagignore
を試すこともできます。 たとえば、 tagignore
を使用すると、特定のラベルを除くすべてのラベルのデータを取得できます。 以下のフィルターは、/ユーザーハンドラー以外のすべてを返します。 この場合、これはworker:purge
およびhttp-path:/messages
です。
(pprof) tagfocus= (pprof) tagignore="http-path:/user" (pprof) tags http-path: Total 70 70 ( 100%): /messages worker: Total 158 158 ( 100%): purge
フィルタリングされたデータを視覚化しようとすると、出力には各ラベルが完全な「コスト」にどれだけの影響を与えるかが示されます。
worker:purge
が0.07を導入し、 messages 0.03s
ハンドラがgenerateID
関数にmessages 0.03s
を導入したことがわかります。
自分で試してみてください!
ラベルを使用すると、単純な呼び出しスタックからは利用できない追加情報をプロファイラーに追加できます。 プロファイラーで追加のディメンションが必要な場合は、 Go 1.9 betaのベータ版をダウンロードして、今すぐ試用できます。 また、 pprofutil
パッケージを使用して、HTTPパスをラベルで自動的にラップします。
Go 1.9 beta 2は現在利用可能です。 既知のバグはありませんが、開発チームはプログラムで試してみて、問題が発生した場合はバグトラッカーに報告してください。 Goをアセンブルし、開発の最先端にいることは非常に簡単です。 アセンブリ自体は1分もかかりません。 がんばれ!