Go開発者ツール:プロファイラーラベルを理解する

描画 こんにちは 私の名前はマルコです。 私はBadooのシステムプログラマです。 Go 1.9の新機能に関するrakyllのすばらしい投稿の翻訳を紹介します。 ラベルはGoプログラムのプロファイリングに非常に役立つと思われます。 たとえば、Badooでは、Cプログラムのコードにタグを付けるために同様のものを使用します。タイマーがトリガーされ、スタックトレースがログに表示される場合、それに加えて、そのようなタグを表示します。 たとえば、特定のUIDを持つユーザーの写真を処理したと言えます。 これは非常に便利であり、Goでも同様の機会が得られたことを非常に嬉しく思います。


プロファイラーラベルはGo 1.9で登場しました。CPUプロファイラーが作成するサンプルにキーと値のペアを追加する機能です。 プロファイラーは、プロセッサーが最も時間を費やす最もホットな機能に関する情報を収集して表示します。 従来のCPUプロファイラーの出力は、関数の名前、ソースファイルの名前、このファイルの行番号などで構成されます。 このデータから、コードのどの部分がこれらのホット関数を呼び出したかを理解することもできます。 出力をフィルタリングして、特定の実行ブランチのより深い概念を取得することもできます。


完全な呼び出しスタックに関する情報は非常に役立ちますが、これはパフォーマンスの問題を見つけるのに必ずしも十分ではありません。 多数のGoプログラマーがGoを使用してサーバーを記述しますが、サーバーのパフォーマンスの問題がどこにあるかを理解することはさらに困難です。 ある実行ブランチを別の実行ブランチから分離することは困難です。または、1つの実行ブランチのみが問題を引き起こす場合(一部のユーザーまたは特定のハンドラー)を理解することは困難です。 Go 1.9からは、現時点で何が起こっているかのコンテキストに関する追加情報を追加し、この情報をプロファイラーで使用して、より孤立したデータを取得する機会があります。


ラベルは多くの場合に役立ちます。 最も明らかなものを次に示します。



ラベルを追加する


runtime/pprofruntime/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-pathworker )とそれぞれにいくつかの値があります。 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 。 そしてこの結論では、最もロードされた場所/ユーザーハンドラがどこにあるかを簡単に理解できます。


追加のフィルタリングのためにtagshowtaghideおよび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分もかかりません。 がんばれ!



Source: https://habr.com/ru/post/J332636/


All Articles