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

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

このコミットは、Go言語のテスト実行フレームワークである test/run.go に関連する変更です。具体的には、クロスコンパイルされたバイナリ(特にGoogle Native Client (NaCl) 向け)のテスト実行時における並列処理の挙動を調整し、リソース消費の問題を緩和することを目的としています。

コミット

commit 4895f0dc5edb8c7f8721f9e9eec15524a283cf4a
Author: Russ Cox <rsc@golang.org>
Date:   Wed May 28 01:01:08 2014 -0400

    test/run: limit parallelism to 1 for cross-exec builds
    
    This matters for NaCl, which seems to swamp my 4-core MacBook Pro otherwise.
    It's not a correctness problem, just a usability problem.
    
    LGTM=bradfitz
    R=bradfitz
    CC=golang-codereviews
    https://golang.org/cl/98600046

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

https://github.com/golang/go/commit/4895f0dc5edb8c7f8721f9e9eec15524a283cf4a

元コミット内容

test/run: limit parallelism to 1 for cross-exec builds

This matters for NaCl, which seems to swamp my 4-core MacBook Pro otherwise.
It's not a correctness problem, just a usability problem.

LGTM=bradfitz
R=bradfitz
CC=golang-codereviews
https://golang.org/cl/98600046

変更の背景

このコミットの背景には、Go言語のテスト実行環境におけるリソース管理の問題があります。特に、異なるアーキテクチャやOS向けにクロスコンパイルされたバイナリ("cross-exec builds")をテストする際に、並列でテストを実行するとシステムリソースを過剰に消費し、開発者のマシン(コミットメッセージでは「4コアのMacBook Pro」と具体的に言及されています)を「swamp」(圧倒する、パンクさせる)という問題が発生していました。

この問題は、特にGoogle Native Client (NaCl) 向けのビルドで顕著でした。NaClは、ブラウザ内でネイティブコードを安全に実行するためのサンドボックス技術であり、Go言語はかつてNaClへのコンパイルをサポートしていました。NaCl環境でテストバイナリを実行する場合、ネイティブ環境での実行とは異なり、エミュレーションやサンドボックスのオーバーヘッドが発生する可能性があります。複数のNaClテストを並列で実行すると、これらのオーバーヘッドが累積し、システム全体のパフォーマンスに悪影響を与えていたと考えられます。

コミットメッセージでは、この問題が「正しさの問題(correctness problem)」ではなく、「使いやすさの問題(usability problem)」であると明記されています。これは、テスト結果の正確性には影響しないものの、開発者の作業効率やマシンの応答性に悪影響を与えることを意味します。この変更は、開発体験の向上とリソースの効率的な利用を目的としています。

前提知識の解説

Go言語のクロスコンパイル (Cross-Compilation)

Go言語は、その強力なクロスコンパイル機能で知られています。これは、あるオペレーティングシステム(OS)やアーキテクチャ上でコンパイルされたGoプログラムが、別のOSやアーキテクチャ上で実行できるバイナリを生成する能力を指します。例えば、macOS上でWindows向けの実行ファイルを、あるいはLinux上でARMプロセッサ向けの実行ファイルを生成することが可能です。

Goのクロスコンパイルは、主に以下の環境変数を設定することで行われます。

  • GOOS: ターゲットとなるOS(例: linux, windows, darwin, android, naclなど)
  • GOARCH: ターゲットとなるCPUアーキテクチャ(例: amd64, 386, arm, arm64など)

これらの変数を設定して go build コマンドを実行すると、指定されたターゲット環境で動作するバイナリが生成されます。この機能は、異なるプラットフォームへのデプロイを非常に容易にします。

Google Native Client (NaCl)

Google Native Client (NaCl) は、Googleが開発した技術で、ウェブブラウザ内でネイティブコード(C/C++など)を安全かつ高速に実行するためのサンドボックス環境を提供します。これにより、ウェブアプリケーションがブラウザのセキュリティモデル内で高性能な処理を実行できるようになります。

Go言語は、Go 1.3のリリース(2014年5月)でNaClへのコンパイルサポートを導入しました。これは、GoプログラムをNaClモジュールとしてコンパイルし、ChromeブラウザなどのNaCl対応環境で実行できるようにするものでした。しかし、その後NaClおよびそのポータブル版であるPNaClは、WebAssemblyなどの新しい技術の台頭により、Googleによってサポートが終了されました。Go言語も、その後のバージョンでNaClサポートを削除しています。

このコミットが行われた2014年5月は、Go言語がNaClサポートを提供していた時期と重なります。そのため、NaCl向けのテスト実行がGoのテストインフラストラクチャにとって重要な考慮事項でした。

test/run.go と Goのテストフレームワーク

test/run.go は、Go言語の標準テストツールの一部であり、Goプロジェクト自体のテストスイートを実行するための内部スクリプトまたはユーティリティです。Go言語のテストは通常、go test コマンドを通じて実行されますが、Goプロジェクトの内部では、より複雑なテストシナリオ(クロスコンパイルされたバイナリの実行、特定の環境設定でのテストなど)を管理するために test/run.go のような補助ツールが使用されることがあります。

Goのテストフレームワークは、デフォルトでテストを並列実行する機能を持っています。これは、マルチコアCPUを最大限に活用し、テスト時間を短縮するために設計されています。並列実行の度合いは、GOMAXPROCS 環境変数や、テスト実行時に指定される並列数フラグによって制御されます。

技術的詳細

このコミットの技術的な核心は、test/run.go 内のテスト並列実行ロジックの変更にあります。

変更前は、テストの並列実行数を制御する *numParallel 変数(おそらくコマンドライン引数 --parallel などで指定される並列数)は、*verbose フラグ(詳細出力モード)が有効な場合にのみ 1 に制限されていました。これは、詳細なログが出力される際に、複数のテストが同時にログを吐き出すことで出力が混ざり合い、可読性が低下するのを防ぐためと考えられます。

変更後は、並列実行数を 1 に制限する条件に、len(findExecCmd()) > 0 という新しい条件が追加されました。 findExecCmd() は、Goのテスト実行環境において、特定のターゲット(特にクロスコンパイルされたバイナリやシミュレータが必要な環境)でテストバイナリを実行するために必要なコマンドを特定する関数であると推測されます。

  • もし findExecCmd() が空でない文字列(または文字列のリスト)を返す場合、それはテストバイナリが通常のネイティブ実行ではなく、特別な実行環境(例: NaClサンドボックス、特定のアーキテクチャのシミュレータなど)を介して実行される必要があることを意味します。
  • このような特殊な実行環境では、テストの起動や実行に通常のネイティブ実行よりも多くのリソースや時間がかかる可能性があります。複数のテストが同時にこのような環境で実行されると、システムリソース(CPU、メモリ、I/O)が飽和し、パフォーマンスの低下やシステムの応答性悪化を引き起こす可能性があります。

したがって、len(findExecCmd()) > 0 という条件が追加されたことで、クロスコンパイルされたバイナリ(特にNaClのような特殊な実行環境を必要とするもの)のテスト時には、自動的に並列実行数が 1 に制限されるようになりました。これにより、リソースの過剰消費を防ぎ、開発者のマシンが「パンクする」のを回避し、テスト実行の「使いやすさ」を向上させています。

この変更は、テストの「正しさ」には影響しないという点が重要です。つまり、並列実行を制限してもテスト結果の信頼性は損なわれません。これは、あくまでリソース管理と開発体験の最適化のための調整です。

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

test/run.go ファイルの main 関数内の並列数設定ロジックが変更されています。

--- a/test/run.go
+++ b/test/run.go
@@ -71,15 +71,15 @@ const maxTests = 5000
 func main() {
 	flag.Parse()
 
-	// Disable parallelism if printing
-	if *verbose {
-		*numParallel = 1
-	}
-
 	goos = os.Getenv("GOOS")
 	goarch = os.Getenv("GOARCH")
 	findExecCmd()
 
+	// Disable parallelism if printing or if using a simulator.
+	if *verbose || len(findExecCmd()) > 0 {
+		*numParallel = 1
+	}
+
 	ratec = make(chan bool, *numParallel)
 	rungatec = make(chan bool, *runoutputLimit)
 	var err error

コアとなるコードの解説

変更は main 関数内で行われています。

  1. 変更前のコード:

    // Disable parallelism if printing
    if *verbose {
        *numParallel = 1
    }
    

    この部分では、*verbose フラグ(コマンドライン引数で詳細出力が有効になっているかを示すブーリアンポインタ)が true の場合、テストの並列実行数 *numParallel1 に設定していました。これは、詳細なテストログが複数の並列テストから同時に出力されることによるログの混在を防ぐための措置です。

  2. 変更後のコード:

    // Disable parallelism if printing or if using a simulator.
    if *verbose || len(findExecCmd()) > 0 {
        *numParallel = 1
    }
    

    変更後、並列数を 1 に制限する条件に || len(findExecCmd()) > 0 が追加されました。

    • || は論理OR演算子です。
    • findExecCmd() は、テストバイナリを実行するために特別なコマンド(例: シミュレータ、サンドボックスランナーなど)が必要かどうかを判断し、そのコマンドを返す関数です。
    • len(findExecCmd()) > 0 は、findExecCmd() が空でない結果を返した場合(つまり、特別な実行コマンドが必要な場合)に true となります。

この変更により、以下のいずれかの条件が満たされた場合に、テストの並列実行数が 1 に制限されるようになりました。

  • 詳細出力モードが有効な場合 (*verbosetrue)
  • テストバイナリの実行に特別なコマンド(シミュレータなど)が必要な場合 (len(findExecCmd()) > 0)

特に後者の条件は、NaClのようなクロスコンパイルターゲットや、特定のアーキテクチャのシミュレータ上でテストを実行する際に、リソース消費を抑えるために導入されました。これにより、開発環境でのテスト実行時のパフォーマンス問題が緩和されます。

関連リンク

  • Go言語のクロスコンパイルに関する公式ドキュメントやブログ記事
  • Google Native Client (NaCl) の歴史とGo言語との関連性に関する情報
  • Go言語のテストフレームワークに関するドキュメント

参考にした情報源リンク

  • Go言語のクロスコンパイルに関する一般的な情報源 (例: Go公式ブログ、Goのドキュメント、技術記事)
  • Google Native Client (NaCl) に関する情報源 (例: Wikipedia、GoのIssueトラッカー、関連する技術記事)
  • Go言語のコードレビューシステム (Gerrit) のリンク: https://golang.org/cl/98600046 (これはコミットメッセージに記載されているGoのコードレビューシステムへのリンクであり、詳細な議論や関連する変更履歴を確認できます。)
  • findExecCmd の具体的な実装については、Goのソースコードリポジトリを参照する必要がありますが、このコミットの文脈からその役割を推測しました。
  • 上記Web検索で得られた情報。