Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 14150] ファイルの概要

このコミットは、Go言語のプロファイリングツールである pprof スクリプトに対する改善を含んでいます。具体的には、プロファイル結果からGoランタイムの内部関数である runtime.settype および runtime.settype_flush を除外するフィルタリング機能の追加と、--svg オプションでSVG形式の出力を生成する際に、生成されるXMLが不正になる問題を修正しています。

コミット

commit bcf88de5ffa1119e8b56a765a076d6a302ae3ecc
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Mon Oct 15 20:49:15 2012 -0700

    pprof: filter out runtime.settype and fix --svg mode to produce valid XML
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6642043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/bcf88de5ffa1119e8b56a765a076d6a302ae3ecc

元コミット内容

pprof: filter out runtime.settype and fix --svg mode to produce valid XML
    
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6642043

変更の背景

このコミットは、Go言語のプロファイリングツール pprof のユーザビリティと出力品質を向上させるために行われました。

  1. runtime.settype のフィルタリング: Goプログラムのプロファイルを取得する際、runtime.settyperuntime.settype_flush といったGoランタイムの内部関数がプロファイル結果に現れることがありました。これらの関数は、Goの型システムやガベージコレクションに関連する内部的な処理であり、通常、アプリケーション開発者がパフォーマンスボトルネックを特定する上で直接的に関心を持つ対象ではありません。プロファイル結果にこれらの内部関数が含まれると、本当に重要なアプリケーションコードのパフォーマンス特性が埋もれてしまい、分析が困難になるという問題がありました。そのため、これらの「興味のない」フレームを自動的に除外することで、よりクリーンで分析しやすいプロファイル結果を提供することが求められました。

  2. SVG出力のXML妥当性問題: pprof は、プロファイルデータを視覚的に表現するためにSVG(Scalable Vector Graphics)形式のグラフを生成する機能を提供しています。SVGはXMLベースの画像フォーマットであり、その構造は厳密なXML仕様に準拠している必要があります。しかし、これまでの pprof の実装では、SVG出力時にプログレス情報やサマリー情報などのテキストメッセージが標準出力に直接 printf で出力されていました。これらのテキストメッセージは、SVGのXML構造の外部に存在するため、生成されたSVGファイルがXMLとして不正な形式となり、SVGビューアやエディタで正しく表示・処理できないという問題が発生していました。このコミットは、SVG出力時にはこれらの余分なテキストメッセージを出力しないようにすることで、XMLの妥当性を確保することを目的としています。

前提知識の解説

  • pprof: Go言語の標準的なプロファイリングツールです。CPU使用率、メモリ割り当て、ゴルーチン、ブロックされた同期操作など、様々な種類のプロファイルデータを収集し、分析・可視化することができます。通常、go tool pprof コマンドとして利用され、プロファイルデータをテキスト形式、グラフ形式(SVGなど)、Web UIなど様々な形式で表示できます。
  • プロファイリング: ソフトウェアの実行中にそのパフォーマンス特性(どの関数が多くのCPU時間を使っているか、どの部分が多くのメモリを消費しているかなど)を測定・分析するプロセスです。これにより、パフォーマンスのボトルネックを特定し、最適化の指針を得ることができます。
  • スタックトレースとフレーム: プロファイルデータは通常、関数呼び出しのスタックトレースとして記録されます。スタックトレースの各エントリは「フレーム」と呼ばれ、特定の関数呼び出しを表します。
  • Goランタイム (runtime): Go言語のプログラムが実行される際に、メモリ管理(ガベージコレクション)、ゴルーチン管理、スケジューリング、システムコールインターフェースなど、低レベルな機能を提供する部分です。runtime パッケージに含まれる関数は、通常、Goコンパイラや標準ライブラリによって内部的に使用されます。
  • runtime.settype / runtime.settype_flush: これらはGoランタイムの内部関数であり、Goの型システムやガベージコレクションの内部動作に関連しています。具体的には、新しい型情報の登録や、型情報のキャッシュのフラッシュなど、メモリ管理やリフレクションの低レベルな側面に関わる可能性があります。これらはアプリケーションのロジックとは直接関係ないため、プロファイル結果から除外されることで、より高レベルなアプリケーションのパフォーマンスに焦点を当てることができます。
  • SVG (Scalable Vector Graphics): XMLベースの2次元ベクターグラフィックス記述言語です。Webブラウザで直接表示でき、拡大・縮小しても画質が劣化しないという特徴があります。XML形式であるため、厳密な構文規則に従う必要があります。
  • XML妥当性: XML文書が、そのDTD(Document Type Definition)やXMLスキーマなどの定義に従っているかどうかを指します。妥当なXMLは、構文的に正しいだけでなく、構造的にも定義されたルールに準拠しています。不正なXMLは、パーサーによってエラーと見なされ、正しく処理されない可能性があります。

技術的詳細

このコミットは、misc/pprof というPerlスクリプトに対して行われています。pprof は元々Googleが開発したプロファイリングツールであり、Go言語の pprof もその影響を強く受けています。このスクリプトは、Goプログラムから生成されたプロファイルデータを解析し、様々な形式で出力する役割を担っています。

変更点は大きく分けて二つです。

  1. runtime.settype のフィルタリング:

    • RemoveUninterestingFrames サブルーチン(関数)に、'runtime.settype''runtime.settype_flush' が「興味のないフレーム」のリストに追加されました。
    • このサブルーチンは、プロファイルデータから特定の関数フレームを除外する役割を担っています。これにより、プロファイル結果のコールスタックからこれらのランタイム内部関数が取り除かれ、よりアプリケーションコードに焦点を当てた分析が可能になります。
  2. SVG出力時のXML妥当性修正:

    • misc/pprof スクリプト内で、プログレス情報やサマリー情報などを標準出力に表示するために使用されていた printf 関数呼び出しが、新しく導入された Infof サブルーチンに置き換えられました。
    • Infof サブルーチンは、$main::opt_svg というグローバル変数が真(つまり --svg オプションが指定されている)の場合には、何も出力せずに return するロジックを含んでいます。
    • これにより、--svg オプションが有効な場合、"Total: %s %s\n""After focusing on '%s': %s %s of %s (%0.1f%%)\n" といった情報メッセージが標準出力に書き込まれなくなります。
    • SVG出力は通常、標準出力にXMLデータとして書き込まれるため、これらの余分なテキストが混入するとXMLの構文が破壊され、結果として不正なSVGファイルが生成されていました。Infof の導入により、SVG出力時には純粋なXMLデータのみが出力されるようになり、XMLの妥当性が保証されます。

コアとなるコードの変更箇所

--- a/misc/pprof
+++ b/misc/pprof
@@ -634,7 +634,7 @@ sub Main() {
       # (only matters when --heapcheck is given but we must be
       # compatible with old branches that did not pass --heapcheck always):
       if ($total != 0) {
-        printf("Total: %s %s\n", Unparse($total), Units());
+        Infof("Total: %s %s\n", Unparse($total), Units());
       }
       PrintText($symbols, $flat, $cumulative, $total, -1);
     } elsif ($main::opt_raw) {\
@@ -931,7 +931,7 @@ sub ProcessProfile {
   if ($focus ne '') {
     $profile = FocusProfile($symbols, $profile, $focus);
     my $focus_count = TotalProfile($profile);
-    printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
+    Infof("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
            $focus,
            Unparse($focus_count), Units(),
            Unparse($total_count), ($focus_count*100.0) / $total_count);
@@ -939,7 +939,7 @@ sub ProcessProfile {
   if ($ignore ne '') {
     $profile = IgnoreProfile($symbols, $profile, $ignore);
     my $ignore_count = TotalProfile($profile);
-    printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
+    Infof("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
            $ignore,
            Unparse($ignore_count), Units(),
            Unparse($total_count),
@@ -1115,6 +1115,15 @@ sub PrintSymbolizedProfile {
   }
 }
 
+# Print information conditionally filtered out depending on the output
+# format.
+sub Infof {
+  my $format = shift;
+  my @args = @_;\
+  return if $main::opt_svg;\
+  printf($format, @args);\
+}
+
 # Print text output
 sub PrintText {
   my $symbols = shift;
@@ -2638,6 +2647,8 @@ sub RemoveUninterestingFrames {
                       'runtime.makemap_c',
                       'runtime.makeslice',
                       'runtime.mal',
+                      'runtime.settype',
+                      'runtime.settype_flush',
                       'runtime.slicebytetostring',
                       'runtime.sliceinttostring',
                       'runtime.stringtoslicebyte',

コアとなるコードの解説

  1. Infof サブルーチンの追加:

    • sub Infof { ... } という新しいPerlサブルーチンが定義されました。
    • このサブルーチンは、printf と同様にフォーマット文字列と可変個の引数を受け取ります。
    • return if $main::opt_svg; という行が重要です。これは、pprof--svg オプション付きで実行されている場合($main::opt_svg が真の場合)には、このサブルーチンが即座に終了し、何も出力しないことを意味します。
    • printf($format, @args); の行は、--svg オプションが指定されていない場合にのみ、通常の printf と同じようにメッセージを標準出力に出力します。
    • この変更により、SVG出力時にはプログレスやサマリーに関するテキストがXMLストリームに混入するのを防ぎ、生成されるSVGファイルのXML妥当性を確保します。
  2. printf から Infof への置き換え:

    • Main サブルーチン内(Total: の出力箇所)と ProcessProfile サブルーチン内(After focusing on: および After ignoring: の出力箇所)で、既存の printf 呼び出しが Infof 呼び出しに置き換えられました。
    • これにより、これらの情報メッセージの出力が Infof サブルーチンの制御下に置かれ、SVGモードでの出力抑制が可能になりました。
  3. RemoveUninterestingFrames の更新:

    • RemoveUninterestingFrames サブルーチン内の「興味のないフレーム」のリストに、'runtime.settype''runtime.settype_flush' が追加されました。
    • このリストに含まれる関数は、プロファイルデータから自動的に除外されます。これにより、Goランタイムの内部的な型関連処理がプロファイル結果に現れるのを防ぎ、よりユーザーが関心を持つアプリケーションコードのパフォーマンスに焦点を当てることができます。

これらの変更は、pprof の出力の品質と分析のしやすさを向上させるための、実用的な改善です。

関連リンク

参考にした情報源リンク