[インデックス 18918] ファイルの概要
このドキュメントは、Goランタイムにおける特定のコミット(インデックス18918)について、その背景、技術的詳細、およびコードの変更点を包括的に解説します。特に、Goのスタック管理とテストにおけるtesting.Short()
の利用に焦点を当てます。
コミット
commit f182a6eec895a6d916ed61e9d6f50a84fd970e69
Author: David du Colombier <0intro@gmail.com>
Date: Fri Mar 21 18:13:23 2014 +0100
runtime: skip stack growth test in short mode
LGTM=dvyukov
R=dvyukov
CC=golang-codereviews
https://golang.org/cl/78410043
---
src/pkg/runtime/stack_test.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/pkg/runtime/stack_test.go b/src/pkg/runtime/stack_test.go
index 6b38af82c1..e131ed94ed 100644
--- a/src/pkg/runtime/stack_test.go
+++ b/src/pkg/runtime/stack_test.go
@@ -123,6 +123,9 @@ func TestStackMem(t *testing.T) {
// Test stack growing in different contexts.
func TestStackGrowth(t *testing.T) {
+\tif testing.Short() {\n+\t\tt.Skip("skipping test in short mode")\n+\t}\n \tt.Parallel()\n \tvar wg sync.WaitGroup
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f182a6eec895a6d916ed61e9d6f50a84fd970e69
元コミット内容
このコミットは、Goランタイムのテストスイートにおいて、スタックの成長をテストするTestStackGrowth
というテストを、go test -short
モードで実行する際にスキップするように変更するものです。
変更の背景
Goのランタイムは、goroutineのスタックを動的に管理し、必要に応じてスタックを拡張(成長)させたり縮小させたりします。この動的なスタック管理は、Goの効率的な並行処理を実現する上で非常に重要な機能です。TestStackGrowth
テストは、このスタック成長メカニズムが様々なコンテキストで正しく機能することを確認するために設計されています。
しかし、スタックの成長をテストするシナリオは、多くのgoroutineの生成、深い再帰、あるいは大量のデータコピーを伴うことがあり、その実行には時間がかかる傾向があります。開発者が日常的にテストを実行する際や、継続的インテグレーション(CI/CD)パイプラインにおいて、全てのテストを毎回実行すると、フィードバックループが長くなり、開発効率が低下する可能性があります。
Goのtesting
パッケージには、このような長時間のテストをスキップするための-short
フラグとtesting.Short()
関数が提供されています。このコミットは、TestStackGrowth
が長時間のテストであるという認識に基づき、開発者がgo test -short
コマンドを使用して迅速なテスト実行を望む場合に、このテストをスキップすることで、テストスイート全体の実行時間を短縮し、開発者の生産性を向上させることを目的としています。
前提知識の解説
Goのスタック管理
Goのgoroutineは、非常に軽量な実行単位であり、それぞれが独自のスタックを持っています。Goランタイムは、これらのスタックを効率的に管理するために、以下の特徴的なメカニズムを採用しています。
- 動的なスタックサイズ: 各goroutineは、最初は比較的小さなスタックサイズ(通常2KB)で開始されます。これにより、多数のgoroutineを効率的に起動できます。
- スタックの成長(Stack Growth): 関数呼び出し時に現在のスタック領域が不足した場合、Goランタイムは自動的にスタックを拡張します。このプロセスでは、通常、現在のスタックサイズの2倍の新しい、より大きな連続したメモリブロックが割り当てられます。その後、古いスタックの内容が新しい場所にコピーされ、関連するポインタが更新されます。
- スタックの縮小(Stack Shrinking): スタックが過剰に拡張され、割り当てられたスペースが不要になった場合、特にガベージコレクションの際に、スタックが縮小されることもあります。
- スタックオーバーフロー: 再帰が深すぎたり、スタックを大量に消費する処理が無限に続いたりすると、スタックが最大制限(通常1GB)を超えてしまい、「fatal error: stack overflow」というパニックが発生します。
TestStackGrowth
のようなテストは、これらのスタックの成長と縮小のメカニズムが、様々な条件下で正しく機能することを確認するために重要です。
go test -short
とtesting.Short()
Goの標準テストツールであるgo test
コマンドは、テストの実行を制御するための様々なフラグを提供しています。その一つが-short
フラグです。
-short
フラグ:go test -short
のようにこのフラグを付けてgo test
を実行すると、テストの実行時間を短縮できます。これは、主に開発中の迅速なテスト実行や、CI/CDパイプラインでの高速な検証ステップのために使用されます。testing.Short()
関数:testing
パッケージが提供するtesting.Short()
関数は、現在のテスト実行が-short
フラグ付きで行われているかどうかをブール値で返します。テストコード内でこの関数をチェックし、true
が返された場合にt.Skip()
を呼び出すことで、特定のテストを条件付きでスキップすることができます。
このメカニズムにより、開発者は長時間のテストと短時間のテストを区別し、必要に応じて実行するテストの範囲を調整することが可能になります。
技術的詳細
このコミットの技術的詳細は、Goのテストフレームワークの慣習と、ランタイムのテストの性質に集約されます。
TestStackGrowth
は、Goランタイムのスタック管理の堅牢性を検証するための重要なテストです。このテストは、以下のようなシナリオをシミュレートする可能性があります。
- 深い再帰呼び出し: スタックが何度も拡張されるような深い再帰関数を呼び出す。
- 多数のgoroutineの起動: それぞれがスタックを消費する多数のgoroutineを同時に起動し、スタックの競合や再割り当ての挙動を確認する。
- スタックを大量に消費するデータ構造: スタック上に大きな配列や構造体を割り当てることで、スタックの成長を強制する。
これらのシナリオは、実際のアプリケーションの動作を模倣し、ランタイムがスタックの成長を効率的かつ正確に処理できることを保証します。しかし、これらの操作はメモリの割り当て、コピー、解放を頻繁に引き起こすため、CPUとメモリリソースを大量に消費し、テストの実行時間を大幅に増加させる可能性があります。
コミットが導入する変更は、testing.Short()
関数を利用して、このようなリソース集約的なテストを「ショートモード」でスキップするという、Goのテストにおける標準的なプラクティスに従っています。これにより、開発者は、完全なテストスイートを実行する必要がない場合に、より迅速なフィードバックを得ることができます。これは、特に開発の初期段階や、CI/CDパイプラインのコミット前チェックなど、高速な検証が求められる場面で非常に有効です。
コアとなるコードの変更箇所
変更はsrc/pkg/runtime/stack_test.go
ファイルに対して行われました。具体的には、TestStackGrowth
関数の冒頭に以下の3行が追加されています。
--- a/src/pkg/runtime/stack_test.go
+++ b/src/pkg/runtime/stack_test.go
@@ -123,6 +123,9 @@ func TestStackMem(t *testing.T) {
// Test stack growing in different contexts.
func TestStackGrowth(t *testing.T) {
+\tif testing.Short() {\n+\t\tt.Skip("skipping test in short mode")\n+\t}\n \tt.Parallel()\n \tvar wg sync.WaitGroup
コアとなるコードの解説
追加されたコードは非常にシンプルですが、その効果は大きいです。
if testing.Short() {
: この行は、testing
パッケージのShort()
関数を呼び出します。この関数は、go test
コマンドが-short
フラグ付きで実行された場合にtrue
を返します。t.Skip("skipping test in short mode")
:testing.Short()
がtrue
を返した場合、この行が実行されます。t.Skip()
は、現在のテストをスキップし、テストの実行をそこで終了させます。引数として渡された文字列は、テストがスキップされた理由としてテスト結果に表示されます。
この変更により、go test -short
コマンドが実行されると、TestStackGrowth
テストは実行されずにスキップされます。これにより、テストスイート全体の実行時間が短縮され、開発プロセスがより効率的になります。完全なテストスイート(-short
フラグなし)を実行する場合には、このテストは通常通り実行され、Goランタイムのスタック成長メカニズムの完全な検証が行われます。
関連リンク
- Go Gerrit Change-List: https://golang.org/cl/78410043
参考にした情報源リンク
testing.Short()
に関する情報:- Goランタイムのスタック成長に関する情報:
- https://studyraid.com/posts/go-goroutine-stack-management/
- https://medium.com/@ankur_anand/go-goroutine-stack-management-a-deep-dive-1b2d3e4f5a6b
- https://simpleapples.com/go-goroutine-stack-growth/
- https://www.cloudflare.com/ja-jp/learning/serverless/go-goroutine-stack-management/
- https://go.dev/src/runtime/stack_test.go
- https://github.com/golang/go/blob/master/src/runtime/stack_test.go
- https://ops.tips/blog/go-stack-size/