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

[インデックス 16936] ファイルの概要

このコミットは、Go言語のランタイムパッケージ内のsrc/pkg/runtime/map_test.goファイルに対する変更です。このファイルは、Goのマップ(map)型の内部動作、特にそのサイズ計算やルックアップ性能に関するテストを定義しています。

コミット

  • コミットハッシュ: 1794880299eaac110dad1fb972c91cb8a6e17086
  • Author: Russ Cox rsc@golang.org
  • Date: Tue Jul 30 23:21:07 2013 -0400

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1794880299eaac110dad1fb972c91cb8a6e17086

元コミット内容

    runtime: fix build on FreeBSD
    
    This is what I get for being talked into a test.
    
    TBR=bradfitz
    CC=golang-dev
    https://golang.org/cl/12045044

変更の背景

このコミットの背景には、FreeBSD環境でのGoランタイムのビルド問題がありました。コミットメッセージの「This is what I get for being talked into a test.」という記述から、以前に導入された特定のテストがFreeBSD環境で問題を引き起こし、ビルドが失敗する原因となっていたことが示唆されます。この変更は、そのビルド問題を修正し、FreeBSD上でのGoの安定性を確保することを目的としています。

具体的には、TestMapSizeというテストが、GOMAXPROCSの値が1より大きい場合に正確な結果を返さない、あるいはFreeBSD環境で予期せぬ動作をする可能性があったため、そのテストの実行条件を調整する必要が生じました。

前提知識の解説

Goランタイム

Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクション、スケジューリング(ゴルーチンの管理)、メモリ割り当て、システムコールインターフェースなどが含まれます。ランタイムはGoプログラムのパフォーマンスと動作に直接影響を与えます。

GOMAXPROCS

GOMAXPROCSは、Goランタイムが同時に実行できるOSスレッドの最大数を制御する環境変数、またはruntime.GOMAXPROCS関数によって設定される値です。これはGoのスケジューラがゴルーチンをどのようにOSスレッドにマッピングし、並行実行するかを決定します。

  • GOMAXPROCS=1の場合、Goスケジューラは一度に1つのOSスレッドしか使用せず、ゴルーチンは協調的にマルチプレックスされます。これは、並行処理のオーバーヘッドが最小限に抑えられるため、特定のベンチマークやテストでより予測可能な結果をもたらすことがあります。
  • GOMAXPROCS > 1の場合、Goスケジューラは複数のOSスレッドを利用し、真の並列実行が可能になります。これにより、マルチコアプロセッサの恩恵を最大限に受けることができますが、テストによってはスレッド間の競合やスケジューリングの非決定性が結果に影響を与える可能性があります。

map_test.go

map_test.goは、Goの組み込み型であるマップ(map)の動作を検証するためのテストファイルです。マップはキーと値のペアを格納するハッシュテーブルであり、その内部実装は複雑です。このテストファイルには、マップの作成、要素の追加・削除、ルックアップ、メモリ使用量など、マップの様々な側面をテストする関数が含まれています。TestMapSize関数は、特定の条件下でのマップのメモリフットプリントを測定することを目的としています。

FreeBSD

FreeBSDは、UNIX系のオープンソースオペレーティングシステムです。Goはクロスプラットフォームをサポートしており、FreeBSDもそのターゲットの一つです。OS固有のシステムコールやスケジューリングの挙動の違いにより、特定のテストやランタイムの動作が他のOS(LinuxやmacOSなど)と異なる場合があります。

技術的詳細

このコミットは、TestMapSizeテストの実行ロジックに条件分岐を追加することで、FreeBSDでのビルド問題を解決しています。

TestMapSizeは、Goのマップが占めるメモリサイズを測定するテストです。このようなメモリ測定テストは、GOMAXPROCSの値によって結果が変動する可能性があります。GOMAXPROCSが1より大きい場合、Goランタイムは複数のOSスレッドを使用してゴルーチンを並行実行します。この並行性により、メモリ割り当てのタイミングやガベージコレクションの挙動が非決定論的になり、マップの正確なサイズ測定が困難になることがあります。

コミットメッセージの「This is what I get for being talked into a test.」は、おそらく以前のコミットでTestMapSizeが導入された際に、GOMAXPROCSが1より大きい環境での潜在的な問題が十分に考慮されていなかったことを示唆しています。FreeBSD環境でこのテストが失敗したことから、特にFreeBSDのスケジューリングやメモリ管理の特性が、このテストの正確性に影響を与えたと考えられます。

修正は、TestMapSizeの冒頭に以下のチェックを追加することです。

if runtime.GOMAXPROCS(-1) != 1 {
    t.Skip("gomaxprocs > 1 - not accurate")
}
  • runtime.GOMAXPROCS(-1): この関数呼び出しは、現在のGOMAXPROCSの値を変更せずに取得します。引数に負の値を渡すと、現在の設定値が返されます。
  • != 1: 取得したGOMAXPROCSの値が1ではない場合、つまり複数のOSスレッドが利用可能な場合を意味します。
  • t.Skip("gomaxprocs > 1 - not accurate"): testing.T型のSkipメソッドを呼び出すことで、現在のテストをスキップします。引数にはスキップ理由のメッセージを渡します。

この変更により、TestMapSizeGOMAXPROCSが1に設定されている環境でのみ実行されるようになります。これにより、テストの実行がより決定論的になり、並行処理による非決定的なメモリ割り当てやガベージコレクションの挙動が結果に影響を与えることを防ぎます。結果として、FreeBSDを含む様々な環境でのビルドの安定性が向上します。

コアとなるコードの変更箇所

--- a/src/pkg/runtime/map_test.go
+++ b/src/pkg/runtime/map_test.go
@@ -373,6 +373,9 @@ func testMapLookups(t *testing.T, m map[string]string) {
 }
 
 func TestMapSize(t *testing.T) {
+	if runtime.GOMAXPROCS(-1) != 1 {
+		t.Skip("gomaxprocs > 1 - not accurate")
+	}
 	var m map[struct{}]struct{}
 	size := bytesPerRun(100, func() {
 		m = make(map[struct{}]struct{})\

コアとなるコードの解説

変更はsrc/pkg/runtime/map_test.goファイルのTestMapSize関数内で行われています。

追加された3行のコードは以下の通りです。

if runtime.GOMAXPROCS(-1) != 1 {
    t.Skip("gomaxprocs > 1 - not accurate")
}

このコードブロックは、TestMapSize関数が実行される前に、現在のGoランタイムのGOMAXPROCS設定をチェックします。

  1. runtime.GOMAXPROCS(-1): これは、現在のGOMAXPROCSの値を返します。引数に-1を渡すことで、値を変更せずに現在の設定値を取得できます。
  2. != 1: 取得したGOMAXPROCSの値が1と等しくない場合、つまりGoランタイムが複数のOSスレッドを使用するように設定されている場合に、条件が真となります。
  3. t.Skip("gomaxprocs > 1 - not accurate"): 条件が真の場合、testing.TオブジェクトのSkipメソッドが呼び出されます。これにより、現在のテスト(TestMapSize)はスキップされ、テスト結果には「スキップされた」として記録されます。メッセージ「gomaxprocs > 1 - not accurate」は、テストがスキップされた理由を明確に示しています。これは、GOMAXPROCSが1より大きい環境では、マップのサイズ測定が正確ではない可能性があるためです。

この変更により、TestMapSizeは、GOMAXPROCS=1の環境でのみ実行されるようになり、並行処理による非決定的な要素がテスト結果に影響を与えることを防ぎ、FreeBSDを含む様々な環境でのビルドの安定性を向上させています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント(runtimeパッケージ、testingパッケージ)
  • Go言語のソースコード(src/pkg/runtime/map_test.go
  • GOMAXPROCSに関する一般的なGo言語のドキュメントや記事
  • FreeBSDに関する一般的な情報
  • Web検索: golang.org/cl/12045044 (このCLの具体的な内容は、GoのコードレビューシステムであるGerritの古いURL形式のため、直接アクセスしても情報が得られない場合がありますが、コミットメッセージからその存在は確認できます。)
  • Web検索: "Go runtime GOMAXPROCS map test accuracy"
  • Web検索: "Go FreeBSD build issues"
  • Web検索: "Go testing.T Skip"
  • Web検索: "Go runtime.GOMAXPROCS -1"