[インデックス 17058] ファイルの概要
このコミットは、Go言語のプロファイリングツールであるruntime/pprof
パッケージにおけるテストの調整と、特定のオペレーティングシステム(OS X、NetBSD、OpenBSD)でのプロファイリングの不正確さに関するバグ情報の更新を目的としています。特に、CPUプロファイルのテストが特定の環境で不安定であった問題に対処し、テストの閾値を緩和することで、より広範な環境でのテストの安定性を確保しています。
コミット
commit 8dc7a31d7796d379d36729f5209d93a898471eac
Author: Russ Cox <rsc@golang.org>
Date: Tue Aug 6 14:49:55 2013 -0400
runtime/pprof: adjust test
NetBSD and OpenBSD are broken like OS X is. Good to know.
Drop required count from avg/2 to avg/3, because the
Plan 9 builder just barely missed avg/2 in one of its runs.
R=golang-dev, dvyukov
CC=golang-dev
https://golang.org/cl/12548043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8dc7a31d7796d379d36729f5209d93a898471eac
元コミット内容
runtime/pprof: adjust test
NetBSD and OpenBSD are broken like OS X is. Good to know.
Drop required count from avg/2 to avg/3, because the
Plan 9 builder just barely missed avg/2 in one of its runs.
R=golang-dev, dvyukov
CC=golang-dev
https://golang.org/cl/12548043
変更の背景
このコミットの背景には、Go言語のプロファイリングツールであるruntime/pprof
が、特定のオペレーティングシステム(特にOS X、NetBSD、OpenBSD)上でCPUプロファイルを正確に取得できないという既知の問題(golang.org/issue/6047
)が存在します。この問題は、OSがプロファイリングシグナルを誤ったスレッドに配信するために発生します。
元々、runtime/pprof
のテストはOS Xでの失敗を無視するように設定されていましたが、NetBSDとOpenBSDでも同様の問題が確認されたため、これらのOSもテストのスキップ対象に追加する必要がありました。
また、CPUプロファイルのテストにおいて、収集されるサンプル数の最小要件が厳しすぎたため、Plan 9のビルド環境でテストが不安定になるという問題も発生していました。具体的には、平均サンプル数の半分(avg/2
)という閾値が、Plan 9環境ではギリギリ満たせないケースがあったため、この閾値を平均の3分の1(avg/3
)に緩和することで、テストの安定性を向上させる必要がありました。
このコミットは、これらの問題を解決し、runtime/pprof
のテストがより堅牢で、様々な環境で安定して動作するように調整することを目的としています。
前提知識の解説
- Go言語のプロファイリング (pprof): Go言語には、プログラムのパフォーマンス特性を分析するためのプロファイリングツールキット
pprof
が標準で提供されています。CPU使用率、メモリ割り当て、ゴルーチン、ブロック、ミューテックス競合など、様々な種類のプロファイルを収集し、視覚化することができます。CPUプロファイルは、プログラムがCPU時間をどこで消費しているかを特定するのに役立ちます。 - CPUプロファイリングの仕組み: CPUプロファイリングは通常、一定の間隔(例えば、100Hz)でプログラムの実行を一時停止し、その時点でのコールスタック(関数呼び出しの履歴)を記録することで行われます。これにより、どの関数がCPU時間を多く消費しているかの統計的な情報が得られます。
- プロファイリングシグナル: OSレベルでは、プロファイリングはシグナル(例えば、Unix系の
SIGPROF
)を使用して実装されることが多いです。このシグナルが定期的にプロセスに送信され、シグナルハンドラがコールスタックを収集します。 - マルチスレッド環境でのプロファイリングの課題: マルチスレッド環境では、プロファイリングシグナルがどのスレッドに配信されるかが重要になります。もしOSがシグナルを誤ったスレッドに配信したり、プロファイリング対象のスレッドがシグナルを受け取れない状態にあったりすると、正確なプロファイルが収集できません。
golang.org/issue/6047
で言及されている問題は、まさにこのシグナル配信の不正確さに起因しています。 runtime.GOOS
: Go言語の標準ライブラリruntime
パッケージには、現在のオペレーティングシステムを示す定数GOOS
が定義されています。例えば、darwin
はmacOS、linux
はLinux、netbsd
はNetBSD、openbsd
はOpenBSDを示します。この定数を利用することで、OSに依存するコードの分岐を行うことができます。- テストの閾値: ソフトウェアテストにおいて、特定の条件が満たされているかを判断するために設定される基準値です。このコミットでは、CPUプロファイルで収集されるサンプル数が、期待される最小値を満たしているかどうかの閾値が調整されています。
技術的詳細
このコミットは、主にsrc/pkg/runtime/pprof/pprof.go
とsrc/pkg/runtime/pprof/pprof_test.go
の2つのファイルに変更を加えています。
-
src/pkg/runtime/pprof/pprof.go
の変更:- 既存の
BUG
コメントが更新されました。以前はOS Xのみが不正確なプロファイルの問題を抱えていると記載されていましたが、NetBSDとOpenBSDも同様の問題を抱えていることが確認されたため、これらのOSも追記されました。 - これはコードの動作には影響しませんが、ドキュメントとして重要な更新であり、ユーザーや開発者に対して既知の制限を明確に伝えます。
- 既存の
-
src/pkg/runtime/pprof/pprof_test.go
の変更:testCPUProfile
関数内で、プロファイルが短すぎる場合の処理が変更されました。- 以前はOS Xでのみ失敗を無視していましたが、
badOS
マップを導入し、darwin
(OS X)、netbsd
、openbsd
のいずれかのOSであれば、テストをスキップするように変更されました。これにより、これらのOS上でのテストの不安定性を回避し、CI/CDパイプラインの安定化に貢献します。t.Skipf
を使用することで、テストがスキップされた理由が明確にログに出力されます。 - それ以外のOSでプロファイルが短すぎる場合は、以前と同様に
t.FailNow()
でテストを即座に失敗させます。
- 以前はOS Xでのみ失敗を無視していましたが、
- CPUプロファイルのサンプル数に関する最小要件が緩和されました。
min := total / uintptr(len(have)) / 2
という計算式が、min := total / uintptr(len(have)) / 3
に変更されました。これは、各関数が収集すべき最小サンプル数を、総サンプル数を関数の数で割った平均値の半分から、平均値の3分の1に引き下げることを意味します。- この変更は、Plan 9ビルド環境でのテストの不安定性に対処するためのものです。Plan 9環境では、プロファイリングの精度が他の環境とわずかに異なり、以前の厳しすぎる閾値ではテストが時折失敗していました。閾値を緩和することで、このような環境でもテストが安定してパスするようになります。
badOS
というグローバルマップが新しく定義されました。- このマップは、キーとしてOS名(文字列)、値としてブール値(
true
)を持ち、プロファイリングテストが失敗することが予想されるOSをリストアップします。これにより、コード内で特定のOSをハードコードするのではなく、一箇所で管理できるようになり、可読性と保守性が向上します。
- このマップは、キーとしてOS名(文字列)、値としてブール値(
これらの変更により、runtime/pprof
のテストは、特定のOSでの既知のプロファイリング問題による影響を受けにくくなり、より堅牢で信頼性の高いものになりました。また、Plan 9のような特定のビルド環境でのテストの不安定性も解消されています。
コアとなるコードの変更箇所
diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go
index 5c1f3d460d..e7eb66a557 100644
--- a/src/pkg/runtime/pprof/pprof.go
+++ b/src/pkg/runtime/pprof/pprof.go
@@ -20,7 +20,8 @@ import (
"text/tabwriter"
)
-// BUG(rsc): Profiles are incomplete and inaccuate on OS X. See http://golang.org/issue/6047 for details.
+// BUG(rsc): Profiles are incomplete and inaccuate on NetBSD, OpenBSD, and OS X.
+// See http://golang.org/issue/6047 for details.
// A Profile is a collection of stack traces showing the call sequences
// that led to instances of a particular event, such as allocation.
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
index 995c2fe68d..040d77a434 100644
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -78,11 +78,12 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
val = val[:l]
if l < 13 {
- if runtime.GOOS == "darwin" {
- t.Logf("ignoring failure on OS X; see golang.org/issue/6047")
+ t.Logf("profile too short: %#x", val)
+ if badOS[runtime.GOOS] {
+ t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
return
}
- t.Fatalf("profile too short: %#x", val)
+ t.FailNow()
}
hd, val, tl := val[:5], val[5:l-3], val[l-3:]
@@ -124,7 +125,7 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
t.Logf("no CPU profile samples collected")
ok = false
}
- min := total / uintptr(len(have)) / 2
+ min := total / uintptr(len(have)) / 3
for i, name := range need {
if have[i] < min {
t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
@@ -133,10 +134,17 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
}
if !ok {
- if runtime.GOOS == "darwin" {
- t.Logf("ignoring failure on OS X; see golang.org/issue/6047")
+ if badOS[runtime.GOOS] {
+ t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
return
}
t.FailNow()
}
}
+
+// Operating systems that are expected to fail the tests. See issue 6047.
+var badOS = map[string]bool{
+ "darwin": true,
+ "netbsd": true,
+ "openbsd": true,
+}
コアとなるコードの解説
src/pkg/runtime/pprof/pprof.go
// BUG(rsc): Profiles are incomplete and inaccuate on NetBSD, OpenBSD, and OS X.
// See http://golang.org/issue/6047 for details.
この変更は、pprof
パッケージのドキュメンテーションコメントを更新し、CPUプロファイルが不完全または不正確になる既知のバグが、OS XだけでなくNetBSDとOpenBSDでも発生することを明記しています。これは、golang.org/issue/6047
で追跡されている問題に関連しており、ユーザーや開発者に対して、これらのOS上でのプロファイリング結果の信頼性に関する注意喚起を促します。
src/pkg/runtime/pprof/pprof_test.go
testCPUProfile
関数の変更点
if l < 13 {
t.Logf("profile too short: %#x", val)
if badOS[runtime.GOOS] {
t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
return
}
t.FailNow()
}
このブロックは、収集されたプロファイルの長さ(l
)が短すぎる場合に実行されます。
t.Logf("profile too short: %#x", val)
: プロファイルが短すぎることをログに出力します。if badOS[runtime.GOOS]
: 新しく導入されたbadOS
マップを使用して、現在のOSがプロファイリングテストで失敗することが予想されるOS(darwin
,netbsd
,openbsd
)のいずれかであるかをチェックします。t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
: もし現在のOSがbadOS
マップに含まれていれば、テストをスキップします。これにより、既知のOS固有のプロファイリング問題によってテストが失敗するのを防ぎ、CI/CDの安定性を向上させます。t.Skipf
は、テストがスキップされた理由を詳細にログに出力します。return
: テストをスキップした後、関数の実行を終了します。t.FailNow()
:badOS
に含まれないOSでプロファイルが短すぎる場合は、テストを即座に失敗させます。これは、予期せぬプロファイリングの問題が発生したことを示します。
min := total / uintptr(len(have)) / 3
この行は、各関数が収集すべき最小サンプル数を計算するロジックを変更しています。
- 以前は
total / uintptr(len(have)) / 2
(総サンプル数を関数の数で割った平均値の半分)でした。 - 変更後は
total / uintptr(len(have)) / 3
(総サンプル数を関数の数で割った平均値の3分の1)になりました。 この変更は、Plan 9ビルド環境でのテストの不安定性に対処するためのものです。プロファイリングの性質上、サンプル数にはある程度のばらつきがあるため、閾値を緩和することで、テストがより堅牢になり、特定の環境での偶発的な失敗を防ぎます。
if !ok {
if badOS[runtime.GOOS] {
t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
return
}
t.FailNow()
}
このブロックは、プロファイルが期待通りに収集されなかった場合(ok
がfalse
の場合)に実行されます。
- ここでも
badOS
マップが使用され、既知の問題を抱えるOSであればテストをスキップします。 - それ以外のOSであれば、
t.FailNow()
でテストを失敗させます。このロジックは、プロファイルの長さが短すぎる場合の処理と同様の目的を持っています。
badOS
マップの定義
// Operating systems that are expected to fail the tests. See issue 6047.
var badOS = map[string]bool{
"darwin": true,
"netbsd": true,
"openbsd": true,
}
この新しいグローバル変数badOS
は、プロファイリングテストが失敗することが予想されるオペレーティングシステムをリストアップするマップです。
- キーは
runtime.GOOS
で返されるOS名(例:"darwin"
,"netbsd"
,"openbsd"
)です。 - 値は
true
で、そのOSが「悪いOS」であることを示します。 このマップを導入することで、テストコード内で特定のOS名をハードコードする代わりに、一元的に管理できるようになり、コードの可読性と保守性が向上します。また、将来的に同様の問題を抱えるOSが追加された場合でも、このマップを更新するだけで対応できます。
関連リンク
- Go言語の変更リスト: https://golang.org/cl/12548043
参考にした情報源リンク
- GitHub Issue 6047: runtime/pprof: multithreaded CPU profiles incorrect on NetBSD: