[インデックス 18777] ファイルの概要
このコミットは、Go言語のランタイムテストスクリプト(run.bash
, run.bat
, run.rc
)に、GOMAXPROCS=2
を設定してランタイムテストを実行する理由を説明するコメントを追加するものです。これにより、並列設定におけるランタイムのブートストラップコード、最初のゴルーチンの作成、および最初のガベージコレクションのテストが意図されていることを明確にしています。
コミット
commit 130458470a11d1f16908d7db7fe683b621541a36
Author: Dmitriy Vyukov <dvyukov@google.com>
Date: Thu Mar 6 13:16:14 2014 +0400
run.bash: explain why we set GOMAXPROCS for runtime test
Fixes #7459.
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/71060044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/130458470a11d1f16908d7db7fe683b621541a36
元コミット内容
このコミットは、Goのテスト実行スクリプトであるrun.bash
、run.bat
、run.rc
に対して、ランタイムテスト時にGOMAXPROCS=2
を設定する理由を説明するコメントを追加するものです。これは、Goの内部イシュートラッカーにおけるイシュー #7459 を修正するために行われました。この変更の目的は、ランタイムのブートストラップコード、特に並列環境での最初のゴルーチン作成やガベージコレクションの動作をテストすることにあります。
変更の背景
Go言語のランタイムは、プログラムの実行を管理する非常に重要な部分です。これには、ゴルーチンのスケジューリング、メモリ管理(ガベージコレクションを含む)、チャネル操作などが含まれます。これらの機能は、特にマルチコア環境で正しく動作することが不可欠です。
以前から、Goのテストスイートでは、ランタイムパッケージのテスト時にGOMAXPROCS=2
という環境変数を設定していました。しかし、この設定がなぜ行われているのか、その意図がコードベースに明示されていませんでした。イシュー #7459 は、この設定の目的を明確にし、テストの意図をドキュメント化することを求めていました。
この変更の主な背景は、以下の点にあります。
- テストの意図の明確化:
GOMAXPROCS=2
という設定は、単にテストを並列で実行するためだけではなく、Goランタイムが並列環境でどのように初期化され、動作するかを検証するためのものでした。特に、ランタイムのブートストラップ(起動)時に行われる並列設定(例:procresize
呼び出し)や、複数のプロセッサが利用可能な状況での最初のゴルーチン作成、および最初のガベージコレクションの挙動をテストすることが重要でした。 - コードの可読性と保守性: テストスクリプトにコメントを追加することで、将来の開発者がこの設定の重要性と目的を理解しやすくなります。これにより、テストの保守性が向上し、意図しない変更によって重要なテストシナリオが失われるリスクが低減されます。
- デバッグと理解の促進: テストが失敗した場合、
GOMAXPROCS=2
が設定されている理由を理解していれば、問題の特定が容易になります。また、Goランタイムの内部動作を学習する開発者にとっても、このコメントは貴重な情報源となります。
要するに、このコミットは、Goランタイムの並列処理に関する重要なテストの意図を明示し、コードベースのドキュメンテーションを改善することを目的としています。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念とテストに関する知識が必要です。
-
GOMAXPROCS
環境変数:GOMAXPROCS
は、Goランタイムが同時に実行できるOSスレッドの最大数を制御する環境変数です。これは、GoスケジューラがゴルーチンをOSスレッドにマッピングする際に利用可能な論理プロセッサの数を決定します。- デフォルトでは、
GOMAXPROCS
は利用可能なCPUコア数に設定されます。 GOMAXPROCS
を1に設定すると、Goプログラムは単一のOSスレッドで実行され、ゴルーチンは協調的にマルチプレックスされます。2以上に設定すると、複数のOSスレッドが利用され、ゴルーチンは並列に実行される可能性があります。- このコミットでは
GOMAXPROCS=2
に設定されており、これはGoランタイムが少なくとも2つのOSスレッドを利用してゴルーチンをスケジュールし、並列処理をシミュレートまたは実行することを意味します。
-
go test -cpu
フラグ:go test
コマンドには、-cpu
フラグがあります。これは、テストを実行する際にGOMAXPROCS
の値を一時的に設定するために使用されます。- 例えば、
go test -cpu=1,2,4
とすると、テストはGOMAXPROCS=1
、GOMAXPROCS=2
、GOMAXPROCS=4
の各設定でそれぞれ実行されます。これにより、異なる並列度でのテスト動作を確認できます。 - このコミットでは、
GOMAXPROCS=2
が環境変数として設定され、さらに-cpu=1,2,4
がテストコマンドに渡されています。これは、テストがGOMAXPROCS=2
の環境下で起動し、その後にテストスイート内でGOMAXPROCS
が1、2、4と切り替わることを意味します。特に、起動時のGOMAXPROCS=2
が重要視されています。
-
Goランタイムのブートストラップコード:
- Goプログラムが起動する際、Goランタイムは初期化処理を行います。これを「ブートストラップ」と呼びます。
- この初期化処理には、スケジューラのセットアップ、メモリ管理システムの初期化、最初のゴルーチン(
main
関数を実行するゴルーチン)の作成などが含まれます。 - 並列環境(
GOMAXPROCS > 1
)では、このブートストラップコードは、複数のプロセッサ(P)を管理するためのデータ構造の初期化や、必要に応じてOSスレッド(M)の起動など、並列処理に特有のロジックを実行します。 - 特に、
procresize
のような関数は、GOMAXPROCS
の値に基づいて利用可能なプロセッサの数を調整し、それに応じてランタイムの状態を更新します。
-
ゴルーチン (Goroutines):
- Go言語の軽量な並行処理単位です。OSスレッドよりもはるかに軽量で、数百万個作成することも可能です。
- Goランタイムのスケジューラによって管理され、OSスレッド上で多重化されて実行されます。
-
ガベージコレクション (Garbage Collection, GC):
- Goランタイムが自動的に不要になったメモリを解放するプロセスです。
- GoのGCは並行(concurrent)かつ並列(parallel)に動作するように設計されており、プログラムの実行と同時にGC処理の一部がバックグラウンドで実行されます。
- 並列設定(
GOMAXPROCS > 1
)でのGCの動作は、単一プロセッサ環境とは異なる挙動を示す可能性があり、テストが重要です。
これらの概念を理解することで、GOMAXPROCS=2
が単なるテストの並列化以上の意味を持ち、Goランタイムの並列処理に関する重要な初期化ロジックと動作を検証するためのものであることが分かります。
技術的詳細
このコミットの技術的詳細は、Goランタイムのテスト戦略と、GOMAXPROCS
環境変数がランタイムの初期化に与える影響に焦点を当てています。
Goランタイムは、プログラムの起動時に複雑な初期化プロセスを実行します。このプロセスには、スケジューラのセットアップ、メモリ管理構造の初期化、そして最初のゴルーチン(main
関数を実行するゴルーチン)の作成が含まれます。これらの初期化ステップは、特に並列環境(GOMAXPROCS > 1
)において、その動作が重要になります。
コミットメッセージと追加されたコメントが示唆するように、GOMAXPROCS=2
を設定してランタイムテストを実行することには、以下の具体的な技術的意図があります。
-
ランタイムのブートストラップコードのテスト:
- Goランタイムのブートストラップコードは、プログラムが開始されるとすぐに実行されます。このコードは、
GOMAXPROCS
の値に基づいて、利用可能な論理プロセッサ(P)の数を設定し、それらを管理するための内部データ構造を初期化します。 - 特に、
procresize
のような関数は、GOMAXPROCS
の値が変更されたときに呼び出され、ランタイムが利用可能なプロセッサの数を動的に調整します。GOMAXPROCS=2
でテストを開始することで、ランタイムが複数のプロセッサを想定して初期化されるシナリオを検証できます。これにより、並列環境でのスケジューラの初期設定や、PとM(OSスレッド)の関連付けが正しく行われることを確認します。
- Goランタイムのブートストラップコードは、プログラムが開始されるとすぐに実行されます。このコードは、
-
並列設定における最初のゴルーチン作成のテスト:
main
関数を実行する最初のゴルーチンは、ランタイムの初期化プロセスの一部として作成されます。GOMAXPROCS=2
の環境下でこの作成プロセスをテストすることで、複数のプロセッサが存在する状況でゴルーチンが正しく初期化され、スケジューラに登録されることを確認します。これは、並行処理の基盤が正しく機能していることを保証するために重要です。
-
並列設定における最初のガベージコレクションのテスト:
- Goのガベージコレクタは、プログラムの実行中に自動的にメモリを管理します。最初のガベージコレクションは、プログラムの起動後比較的早い段階で発生する可能性があります。
GOMAXPROCS=2
の環境で最初のGCをテストすることは、GCが並列に動作する際に、複数のプロセッサを効率的に利用し、競合状態やデッドロックなしに正しく機能することを確認するために不可欠です。特に、GCの初期化フェーズや、複数のM(OSスレッド)がGC作業に参加する際の同期メカニズムが正しく動作するかを検証します。
-
GOMAXPROCS
と-cpu
フラグの組み合わせ:- このコミットでは、
GOMAXPROCS=2
を環境変数として設定し、さらにgo test runtime -cpu=1,2,4
を実行しています。 - 環境変数としての
GOMAXPROCS=2
は、テストプロセス全体の初期GOMAXPROCS
値を設定します。これにより、テストスイートが起動する時点でのランタイムの並列設定を制御します。 - 一方、
-cpu=1,2,4
フラグは、テストスイート内でGOMAXPROCS
の値を動的に変更し、それぞれの設定でテストを再実行します。 - この組み合わせにより、ランタイムのブートストラップが
GOMAXPROCS=2
の状態で始まり、その後、異なる並列度(1、2、4)でのランタイムの動作もテストされるという、より包括的なテストカバレッジが実現されます。特に、起動時のGOMAXPROCS=2
が、並列環境でのランタイムの初期化ロジックを検証する上で重要であると強調されています。
- このコミットでは、
これらの技術的側面を考慮すると、このコミットは単なるコメントの追加以上の意味を持ち、Goランタイムの堅牢性を確保するための重要なテスト戦略の一部を明確にしています。
コアとなるコードの変更箇所
このコミットによる変更は、主にGoのテスト実行スクリプトであるsrc/run.bash
、src/run.bat
、src/run.rc
にコメントを追加するものです。
src/run.bash
の変更
--- a/src/run.bash
+++ b/src/run.bash
@@ -54,6 +54,8 @@ echo '# Testing packages.'
time go test std -short -timeout=$(expr 120 \* $timeout_scale)s
echo
+# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+# creation of first goroutines and first garbage collections in the parallel setting.
echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
GOMAXPROCS=2 go test runtime -short -timeout=$(expr 300 \* $timeout_scale)s -cpu=1,2,4
echo
src/run.bat
の変更
--- a/src/run.bat
+++ b/src/run.bat
@@ -42,11 +42,19 @@ go test std -short -timeout=120s
if errorlevel 1 goto fail
echo.
-echo # runtime -cpu=1,2,4
+set OLDGOMAXPROCS=%GOMAXPROCS%
+
+:: We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+:: creation of first goroutines and first garbage collections in the parallel setting.
+echo # GOMAXPROCS=2 runtime -cpu=1,2,4
+set GOMAXPROCS=2
go test runtime -short -timeout=300s -cpu=1,2,4
if errorlevel 1 goto fail
echo.
+set GOMAXPROCS=%OLDGOMAXPROCS%
+set OLDGOMAXPROCS=
+
echo # sync -cpu=10
go test sync -short -timeout=120s -cpu=10
if errorlevel 1 goto fail
src/run.rc
の変更
--- a/src/run.rc
+++ b/src/run.rc
@@ -32,6 +32,8 @@ echo '# Testing packages.'
time go test std -short -timeout 120s
echo
+# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+# creation of first goroutines and first garbage collections in the parallel setting.
echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
GOMAXPROCS=2 go test runtime -short -timeout 240s -cpu 1,2,4
echo
これらの変更は、既存のGOMAXPROCS=2 go test runtime ...
コマンドの直前または周辺に、その設定の理由を説明するコメントを追加しています。src/run.bat
では、GOMAXPROCS
の値を一時的に設定し、テスト後に元の値に戻すためのロジックも追加されています。
コアとなるコードの解説
追加されたコメントは、GoランタイムのテストにおけるGOMAXPROCS=2
設定の具体的な目的を明確にしています。
# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
# creation of first goroutines and first garbage collections in the parallel setting.
このコメントは、以下の重要な点を説明しています。
-
GOMAXPROCS=2
の設定:- これは、Goランタイムのテストを実行する際に、Goスケジューラが利用できるOSスレッドの数を2に制限することを意味します。これにより、テストは少なくとも2つの論理プロセッサが利用可能な並列環境で実行されます。
-
-cpu=1,2,4
との組み合わせ:go test
コマンドに渡される-cpu=1,2,4
フラグは、テストスイート内でGOMAXPROCS
の値を1、2、4と切り替えて、それぞれの設定でテストを再実行します。- しかし、このコメントは、環境変数として設定された
GOMAXPROCS=2
が、-cpu
フラグによるテストとは別に、特に重要であることを強調しています。これは、テストプロセスが起動する時点でのランタイムの初期化(ブートストラップ)が、GOMAXPROCS=2
の並列設定で行われることを保証するためです。
-
テストの目的:
- ランタイムのブートストラップコード: Goプログラムが起動する際のランタイムの初期化処理をテストします。これには、スケジューラのセットアップや、並列環境でのプロセッサ管理などが含まれます。
GOMAXPROCS=2
で起動することで、これらの初期化ロジックが複数のプロセッサを想定して正しく動作するかを検証します。 - 最初のゴルーチンの作成:
main
関数を実行する最初のゴルーチンが、並列設定下で正しく作成され、スケジューラに登録されることをテストします。 - 並列設定における最初のガベージコレクション: プログラム起動後、比較的早い段階で発生する可能性のある最初のガベージコレクションが、並列環境で正しく機能するかをテストします。これには、複数のOSスレッドがGC作業に参加する際の同期や効率性が含まれます。
- ランタイムのブートストラップコード: Goプログラムが起動する際のランタイムの初期化処理をテストします。これには、スケジューラのセットアップや、並列環境でのプロセッサ管理などが含まれます。
src/run.bat
では、set OLDGOMAXPROCS=%GOMAXPROCS%
とset GOMAXPROCS=%OLDGOMAXPROCS%
が追加されており、これはテスト実行前後のGOMAXPROCS
環境変数の値を保存・復元することで、テストが他の環境設定に影響を与えないようにするための配慮です。
これらの変更は、Goランタイムの並列処理に関する重要な初期化と動作を検証するためのテストの意図を明確にし、テストスクリプトの可読性と保守性を向上させています。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/130458470a11d1f16908d7db7fe683b621541a36
- Go Code Review (CL): https://golang.org/cl/71060044
参考にした情報源リンク
- Go Code Review (CL) 71060044: https://golang.org/cl/71060044
- Go言語の
GOMAXPROCS
に関するドキュメント (Goの公式ドキュメントやブログ記事など、一般的な情報源) - Goランタイムの内部構造に関する情報 (Goのソースコードや関連する技術記事など)
- Goのテストに関するドキュメント (Goの公式ドキュメント)