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

[インデックス 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 の実行時間を延長: テスト内の triescount の値を増やすことで、テストがより多くのゴルーチンスイッチングをシミュレートするようにしました。
  • 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 関数内の triescount 変数の初期値にあります。

  • tries: この変数は、TestGoroutineSwitch が実行するテストの反復回数を制御します。元のコミットでは 4000000 に設定されていましたが、このコミットでは元の 10 に戻されています。
  • count: この変数は、各テストの反復内で実行されるゴルーチンスイッチングの回数、またはテストの「重さ」を制御します。元のコミットでは 4000000 に設定されていましたが、このコミットでは元の 1000000 に戻されています。

これらの変更により、TestGoroutineSwitch の実行時間は大幅に短縮されます。testing.Short()true の場合(go test -short で実行された場合)、tries1 に設定され、テストはさらに高速に完了します。

コメントも更新されており、テストの実行時間の目安が「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公式ドキュメント)