[インデックス 17680] ファイルの概要
このコミットは、Goランタイムのプロファイリングテストに関する以前の変更(コミットハッシュ 9567c5da6e25
、CL 13321048
)を元に戻すものです。元の変更は TestGoroutineSwitch
の実行時間を長くすることで、特定のテストの失敗(Issue #6417 に関連)に対処しようとしましたが、このコミットではその変更がビルドプロセスを不必要に遅くすると判断され、より根本的な解決策(パーサーの修正)が模索されることになりました。
コミット
commit 0fc9db794492323e0a4b8c7bf8c8f4069257f58a
Author: Russ Cox <rsc@golang.org>
Date: Mon Sep 23 15:58:35 2013 -0400
undo CL 13321048 / 9567c5da6e25
Makes build unnecessarily slower. Will fix the parser instead.
««« original CL description
runtime/pprof: run TestGoroutineSwitch for longer
Short test now takes about 0.5 second here.
Fixes #6417.
The failure was also seen on our builders.
R=golang-dev, minux.ma, r
CC=golang-dev
https://golang.org/cl/13321048
»»»
R=golang-dev, minux.ma
CC=golang-dev
https://golang.org/cl/13720048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0fc9db794492323e0a4b8c7bf8c8f4069257f58a
元コミット内容
このコミットが元に戻している元のコミット(CL 13321048 / 9567c5da6e25)は、src/pkg/runtime/pprof/pprof_test.go
内の TestGoroutineSwitch
テストの実行時間を長くすることを目的としていました。元のコミットの目的は以下の通りです。
TestGoroutineSwitch
の実行時間を延長: テスト内のtries
とcount
の値を増やすことで、テストがより多くのゴルーチンスイッチングをシミュレートするようにしました。- Issue #6417 の修正: このテストの失敗が Issue #6417 に関連しており、ビルド環境でも同様の失敗が確認されていたため、テストを長く実行することで問題を再現し、修正を検証しようとしました。
- スタック再スキャンの修正: 関連する情報源によると、CL 13321048 は「runtime: fix stack re-scan during stack growth」(スタック成長時のスタック再スキャンを修正)というタイトルであり、スタック成長時のガベージコレクションとポインタ処理に関連するバグに対処することを意図していました。
変更の背景
このコミットは、以前の変更(CL 13321048)がGoのビルドプロセスを不必要に遅くするという副作用があったため、それを元に戻すことを目的としています。元の変更は TestGoroutineSwitch
の実行時間を長くすることで、特定のテストの失敗に対処しようとしましたが、そのアプローチはビルド全体の効率を低下させると判断されました。
コミットメッセージの「Makes build unnecessarily slower. Will fix the parser instead.」という記述は、元の変更がテストの実行時間を延ばすことで問題を「ごまかしていた」に過ぎず、根本的な原因はGoランタイムのパーサー(おそらくスタックのスキャンやガベージコレクションに関連する部分)にあると開発者が判断したことを示唆しています。したがって、テストの実行時間を長くするのではなく、問題の根本原因であるパーサーを修正する方が適切であるという方針転換が行われました。
前提知識の解説
Goランタイム (Go Runtime)
Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクション(GC)、ゴルーチン(軽量スレッド)のスケジューリング、メモリ管理、スタック管理などが含まれます。Goプログラムは、オペレーティングシステムによって直接実行されるのではなく、Goランタイム上で動作します。
プロファイリング (Profiling) と runtime/pprof
プロファイリングは、プログラムのパフォーマンス特性(CPU使用率、メモリ使用量、ゴルーチンの状態など)を測定・分析するプロセスです。Goには標準ライブラリとして runtime/pprof
パッケージが提供されており、これによりGoプログラムのプロファイリングデータを収集できます。収集されたデータは、go tool pprof
コマンドなどを用いて可視化・分析され、パフォーマンスのボトルネック特定に役立てられます。
ゴルーチン (Goroutine)
ゴルーチンは、Goにおける軽量な並行処理の単位です。OSのスレッドよりもはるかに軽量で、数千から数百万のゴルーチンを同時に実行できます。ゴルーチンはGoランタイムによってスケジューリングされ、必要に応じてスタックサイズを動的に増減させることができます。
スタック成長 (Stack Growth)
Goのゴルーチンは、最初は小さなスタック(通常は数KB)で開始されます。関数呼び出しが深くなったり、大きなローカル変数が確保されたりしてスタック領域が不足すると、Goランタイムは自動的に現在のスタックよりも大きな新しいスタック領域を割り当て、古いスタックの内容を新しいスタックにコピーし、ポインタを更新します。このプロセスをスタック成長と呼びます。スタック成長は透過的に行われますが、その過程でガベージコレクタがスタック上のポインタを正確にスキャンできる必要があります。
ガベージコレクション (Garbage Collection)
Goは自動メモリ管理(ガベージコレクション)を採用しています。ガベージコレクタは、プログラムがもはや参照しないメモリ領域を自動的に解放し、再利用可能にします。ガベージコレクタは、プログラムの実行中に定期的に動作し、到達可能なオブジェクトを特定するためにメモリをスキャンします。このスキャンには、ゴルーチンのスタック上に存在するポインタも含まれます。スタック成長中にガベージコレクタが動作すると、スタックの再スキャンが正しく行われないと、メモリリークやクラッシュなどの問題が発生する可能性があります。
testing
パッケージと testing.Short()
Goの標準ライブラリ testing
パッケージは、ユニットテスト、ベンチマークテスト、および例の記述をサポートします。
testing.Short()
は、テストが短時間で実行できるかどうかを示すブール値を返します。go test -short
コマンドでテストを実行すると testing.Short()
は true
を返し、テストスイート全体を高速に実行したい場合に、時間のかかるテストをスキップしたり、テストの反復回数を減らしたりするために使用されます。
技術的詳細
このコミットは、TestGoroutineSwitch
というテストの実行パラメータを元に戻すことで、Goのビルド時間を短縮することを目的としています。
元のコミット(CL 13321048)は、TestGoroutineSwitch
が特定の条件下で失敗する問題(Issue #6417 に関連)に対処するために、テストの実行回数を増やしました。具体的には、tries
変数を 10
から 4000000
に、count
変数を 1000000
から 4000000
に変更しました。これにより、テストはより多くのゴルーチンスイッチングとスタック成長のシナリオを網羅し、問題の再現性を高め、修正を検証しようとしました。
しかし、この変更は TestGoroutineSwitch
の実行時間を大幅に増加させました。コミットメッセージにある「Short test now takes about 0.5 second here.」という記述は、元の変更によってテストが短時間モードでも0.5秒かかるようになったことを示しています。そして、このコミットでは「These defaults take about 6 seconds on a 2011 Windows 7 64 bit notebook. The ones in short mode take about 0.6 seconds.」とあり、元の変更がテスト時間を大幅に延ばしたことがわかります。
Russ Cox氏(Goの主要開発者の一人)は、このテスト時間の増加が「Makes build unnecessarily slower」(ビルドを不必要に遅くする)と判断しました。継続的インテグレーション(CI)システムでは、テストスイート全体の実行時間がビルドの完了時間に直結するため、個々のテストが不必要に長くなることは開発サイクル全体の効率を低下させます。
さらに重要なのは、「Will fix the parser instead.」というコメントです。これは、TestGoroutineSwitch
の失敗が、テストの実行時間を長くすることで対処すべき問題ではなく、Goランタイムのパーサー(おそらくスタックのスキャンやガベージコレクションに関連する部分)に根本的な原因があるという認識を示しています。CL 13321048 が「runtime: fix stack re-scan during stack growth」というタイトルであったことを考慮すると、スタック成長時のスタック再スキャン処理に問題があり、それが TestGoroutineSwitch
の失敗を引き起こしていたと考えられます。元のコミットはその問題を修正しようとしましたが、テストの実行時間を延ばすという副作用があったため、より効率的で根本的な解決策として、パーサーレベルでの修正が計画されたということです。
したがって、このコミットは、一時的な対処療法であったテスト時間の延長を元に戻し、より根本的な解決策に焦点を当てるというGo開発チームの方針転換を反映しています。
コアとなるコードの変更箇所
src/pkg/runtime/pprof/pprof_test.go
ファイルが変更されています。
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -183,11 +183,11 @@ func TestCPUProfileWithFork(t *testing.T) {
// If it did, it would see inconsistent state and would either record an incorrect stack
// or crash because the stack was malformed.
func TestGoroutineSwitch(t *testing.T) {
- // How much to try. These defaults take about 6 seconds
- // on a 2011 Windows 7 64 bit notebook. The ones in short mode take
- // about 0.6 seconds.
+ // How much to try. These defaults take about 1 seconds
+ // on a 2012 MacBook Pro. The ones in short mode take
+ // about 0.1 seconds.
tries := 10
- count := 4000000
+ count := 1000000
if testing.Short() {
tries = 1
}
コアとなるコードの解説
変更は TestGoroutineSwitch
関数内の tries
と count
変数の初期値にあります。
tries
: この変数は、TestGoroutineSwitch
が実行するテストの反復回数を制御します。元のコミットでは4000000
に設定されていましたが、このコミットでは元の10
に戻されています。count
: この変数は、各テストの反復内で実行されるゴルーチンスイッチングの回数、またはテストの「重さ」を制御します。元のコミットでは4000000
に設定されていましたが、このコミットでは元の1000000
に戻されています。
これらの変更により、TestGoroutineSwitch
の実行時間は大幅に短縮されます。testing.Short()
が true
の場合(go test -short
で実行された場合)、tries
は 1
に設定され、テストはさらに高速に完了します。
コメントも更新されており、テストの実行時間の目安が「2011 Windows 7 64 bit notebook で約6秒、ショートモードで約0.6秒」から「2012 MacBook Pro で約1秒、ショートモードで約0.1秒」に変更されています。これは、テストの実行時間が短縮されたことを反映しています。
この変更は、テストの実行時間を短縮することで、Goのビルドプロセス全体の効率を改善することを目的としています。
関連リンク
- 元のコミット (CL 13321048): https://golang.org/cl/13321048
- このコミット (CL 13720048): https://golang.org/cl/13720048
- 関連する可能性のあるIssue #6417: コミットメッセージに記載されていますが、一般的なGoのIssueトラッカーでは直接的な関連が見つかりませんでした。これは内部的な追跡番号であるか、非常に古いIssueである可能性があります。
参考にした情報源リンク
- Go CL 13321048 の情報 (Web検索結果)
- Goのプロファイリングに関する一般的な情報 (Go公式ドキュメントなど)
- Goのガベージコレクションとスタック管理に関する一般的な情報 (Go公式ドキュメント、ブログ記事など)
testing
パッケージのドキュメント (Go公式ドキュメント)