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

[インデックス 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 -shorttesting.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ランタイムのスタック管理の堅牢性を検証するための重要なテストです。このテストは、以下のようなシナリオをシミュレートする可能性があります。

  1. 深い再帰呼び出し: スタックが何度も拡張されるような深い再帰関数を呼び出す。
  2. 多数のgoroutineの起動: それぞれがスタックを消費する多数のgoroutineを同時に起動し、スタックの競合や再割り当ての挙動を確認する。
  3. スタックを大量に消費するデータ構造: スタック上に大きな配列や構造体を割り当てることで、スタックの成長を強制する。

これらのシナリオは、実際のアプリケーションの動作を模倣し、ランタイムがスタックの成長を効率的かつ正確に処理できることを保証します。しかし、これらの操作はメモリの割り当て、コピー、解放を頻繁に引き起こすため、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

コアとなるコードの解説

追加されたコードは非常にシンプルですが、その効果は大きいです。

  1. if testing.Short() {: この行は、testingパッケージのShort()関数を呼び出します。この関数は、go testコマンドが-shortフラグ付きで実行された場合にtrueを返します。
  2. t.Skip("skipping test in short mode"): testing.Short()trueを返した場合、この行が実行されます。t.Skip()は、現在のテストをスキップし、テストの実行をそこで終了させます。引数として渡された文字列は、テストがスキップされた理由としてテスト結果に表示されます。

この変更により、go test -shortコマンドが実行されると、TestStackGrowthテストは実行されずにスキップされます。これにより、テストスイート全体の実行時間が短縮され、開発プロセスがより効率的になります。完全なテストスイート(-shortフラグなし)を実行する場合には、このテストは通常通り実行され、Goランタイムのスタック成長メカニズムの完全な検証が行われます。

関連リンク

参考にした情報源リンク