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

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

このコミットは、Go言語のテスト実行スクリプトである test/run.go における並列テスト実行の設定を変更するものです。特に、ARMアーキテクチャのシステムにおいて、テストが利用可能な全てのCPUコアを使用できるように修正し、テストの並列実行数をより適切に設定することを目的としています。

コミット

このコミットは、Go言語のテストスイート実行時に、ARMシステム上で利用可能な全てのCPUコアをテストの並列実行に活用できるようにする変更です。以前は、ARMシステムではテストの並列実行数が1に制限されていましたが、この制限が撤廃されました。また、デフォルトの並列テスト実行数も 2 * runtime.NumCPU() から runtime.NumCPU() に変更されています。

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

https://github.com/golang/go/commit/47ee98253e88805f7ff46c4b010818e1ca4c7713

元コミット内容

commit 47ee98253e88805f7ff46c4b010818e1ca4c7713
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Wed Mar 7 12:43:25 2012 +0800

    test/run: use all available cores on ARM system
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/5753054
---
 test/run.go | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/test/run.go b/test/run.go
index f0b2555db0..593e4ade64 100644
--- a/test/run.go
+++ b/test/run.go
@@ -30,7 +30,7 @@ import (
 
  var (
  	verbose     = flag.Bool("v", false, "verbose. if set, parallelism is set to 1.")
-	numParallel = flag.Int("n", 2*runtime.NumCPU(), "number of parallel tests to run")
+	numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
  	summary     = flag.Bool("summary", false, "show summary of results")
  	showSkips   = flag.Bool("show_skips", false, "show skipped tests")
  )
@@ -60,10 +60,9 @@ const maxTests = 5000
 
  func main() {
  	flag.Parse()
-	
-	// Disable parallelism if printing, or if running on
-	// (presumably underpowered) arm systems.
-	if *verbose || runtime.GOARCH == "arm" {
+
+	// Disable parallelism if printing
+	if *verbose {
  		*numParallel = 1
  	}
 

変更の背景

この変更の背景には、Go言語のテスト実行環境における効率性と、特定のアーキテクチャ(ARM)に対する最適化の必要性があります。

元々、test/run.go スクリプトは、テストの並列実行数を 2 * runtime.NumCPU() に設定していました。これは、利用可能なCPUコア数の2倍のスレッドでテストを実行することで、I/OバウンドなテストなどにおいてCPUを最大限に活用し、テスト時間を短縮しようとする意図があったと考えられます。

しかし、同時に、runtime.GOARCH == "arm" の場合に並列実行数を1に制限するロジックが存在していました。このコメントには「(presumably underpowered) arm systems.」(おそらく非力なARMシステム)とあり、当時のARMシステムがテストの並列実行に十分な性能を持たない、あるいは並列実行によって不安定になる可能性が考慮されていたことが伺えます。

このコミットは、この「非力」という前提がもはや適切ではない、あるいはARMシステム上でのテスト実行の安定性が向上したため、ARMシステムでも他のアーキテクチャと同様に並列テストを実行できるようにする必要があるという認識に基づいています。ARMシステムがより高性能になり、Goのランタイムやツールチェインが成熟したことで、この制限が不要になった、あるいはパフォーマンス上のボトルネックになっていた可能性が高いです。

また、デフォルトの並列実行数を 2 * runtime.NumCPU() から runtime.NumCPU() に変更したことは、一般的なシステムにおいて、CPUコア数の2倍の並列度が必ずしも最適ではない、あるいは過剰なリソース消費につながる可能性があるという判断があったことを示唆しています。runtime.NumCPU() は、システムが提供する論理CPUコア数に合わせた、より保守的で安定したデフォルト値と言えます。

前提知識の解説

Go言語の runtime パッケージと runtime.NumCPU()

Go言語の runtime パッケージは、Goランタイムとの相互作用を可能にする機能を提供します。その中の runtime.NumCPU() 関数は、現在のシステムが利用可能な論理CPUコアの数を返します。これは、並列処理を行うアプリケーションが、システムのハードウェアリソースを最大限に活用するための基準としてよく使用されます。例えば、並列処理を行うゴルーチンの数を runtime.NumCPU() に基づいて決定することで、CPUバウンドなタスクにおいて最適なパフォーマンスを引き出すことができます。

テストの並列実行

ソフトウェア開発において、テストはコードの品質を保証するために不可欠です。特に大規模なプロジェクトでは、テストスイートの実行に時間がかかることが課題となります。テストの並列実行は、複数のテストを同時に実行することで、テストスイート全体の実行時間を短縮する手法です。Go言語の testing パッケージは、t.Parallel() メソッドを通じてテストの並列実行をサポートしています。

しかし、テストの並列実行には注意が必要です。

  • リソース競合: 複数のテストが同時にファイルシステム、ネットワーク、データベースなどの共有リソースにアクセスする場合、競合が発生し、テストが不安定になったり、誤った結果を返したりする可能性があります。
  • デッドロック/ライブロック: 並列実行されるテスト間で不適切な同期が行われると、デッドロックやライブロックが発生し、テストがハングアップすることがあります。
  • CPU/メモリ負荷: 過度な並列実行は、システムのリソース(CPU、メモリ)を枯渇させ、システムの応答性を低下させたり、テスト実行自体を遅くしたりする可能性があります。

ARMアーキテクチャ

ARM(Advanced RISC Machine)は、モバイルデバイス、組み込みシステム、最近ではサーバーやデスクトップPCにも広く採用されているCPUアーキテクチャです。x86アーキテクチャと比較して、一般的に消費電力が低く、電力効率に優れているという特徴があります。

2012年当時、ARMプロセッサは主にスマートフォンやタブレットなどの低消費電力デバイスに搭載されており、その性能はデスクトップやサーバー向けのx86プロセッサに比べて限定的であるという認識が一般的でした。そのため、Goのテストスクリプトにおいて「おそらく非力なARMシステム」というコメントが付与され、並列実行が制限されていた背景があります。しかし、その後の技術進歩により、ARMプロセッサの性能は飛躍的に向上し、高性能コンピューティングの分野でも利用されるようになっています。

技術的詳細

このコミットは、test/run.go ファイル内の2つの主要な変更点を含んでいます。

  1. numParallel 変数の初期値の変更:

    • 変更前: numParallel = flag.Int("n", 2*runtime.NumCPU(), "number of parallel tests to run")
    • 変更後: numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")

    numParallel は、コマンドライン引数 -n で指定されない場合の、並列テスト実行数のデフォルト値を定義しています。変更前は、システムが持つ論理CPUコア数の2倍の並列度をデフォルトとしていましたが、変更後はCPUコア数と同じ値がデフォルトとなりました。これは、テスト実行におけるリソース消費のバランスを見直し、より安定したデフォルト値を提供することを意図しています。2*runtime.NumCPU() は、I/Oバウンドなワークロードでは有効な場合がありますが、CPUバウンドなテストではコンテキストスイッチのオーバーヘッドが増加し、かえってパフォーマンスが低下する可能性もあります。runtime.NumCPU() は、CPUバウンドなタスクにおいて一般的に推奨される並列度です。

  2. ARMシステムにおける並列実行制限の撤廃:

    • 変更前:
      	// Disable parallelism if printing, or if running on
      	// (presumably underpowered) arm systems.
      	if *verbose || runtime.GOARCH == "arm" {
      		*numParallel = 1
      	}
      
    • 変更後:
      	// Disable parallelism if printing
      	if *verbose {
      		*numParallel = 1
      	}
      

    この変更により、runtime.GOARCH == "arm" という条件が if 文から削除されました。これにより、ARMアーキテクチャのシステム上でも、他のアーキテクチャと同様に、numParallel で設定された値(デフォルトでは runtime.NumCPU())に基づいてテストが並列実行されるようになります。*verbose フラグが設定されている場合(詳細出力モード)には、引き続き並列実行が1に制限されますが、これは出力の混在を防ぐための一般的なプラクティスです。

これらの変更は、Go言語のテストインフラストラクチャが、進化するハードウェア環境、特にARMシステムの性能向上に適応し、より効率的で現実的なテスト実行戦略を採用したことを示しています。

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

--- a/test/run.go
+++ b/test/run.go
@@ -30,7 +30,7 @@ import (
 
  var (
  	verbose     = flag.Bool("v", false, "verbose. if set, parallelism is set to 1.")
-	numParallel = flag.Int("n", 2*runtime.NumCPU(), "number of parallel tests to run")
+	numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
  	summary     = flag.Bool("summary", false, "show summary of results")
  	showSkips   = flag.Bool("show_skips", false, "show skipped tests")
  )
@@ -60,10 +60,9 @@ const maxTests = 5000
 
  func main() {
  	flag.Parse()
-	
-	// Disable parallelism if printing, or if running on
-	// (presumably underpowered) arm systems.
-	if *verbose || runtime.GOARCH == "arm" {
+
+	// Disable parallelism if printing
+	if *verbose {
  		*numParallel = 1
  	}
 

コアとなるコードの解説

numParallel の初期値変更

-	numParallel = flag.Int("n", 2*runtime.NumCPU(), "number of parallel tests to run")
+	numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")

この行は、numParallel という整数型のフラグを定義しています。このフラグは、テストを並列で実行する際の並列度(同時に実行するテストの数)を制御します。

  • 変更前は、デフォルト値として 2*runtime.NumCPU() が設定されていました。これは、システムが持つ論理CPUコア数の2倍の並列度を意味します。
  • 変更後は、デフォルト値が runtime.NumCPU() に変更されました。これは、システムが持つ論理CPUコア数と同じ並列度を意味します。

この変更は、テスト実行時のリソース消費をより適切に管理し、過度な並列実行によるオーバーヘッドを避けるための調整と考えられます。多くのCPUバウンドなワークロードでは、CPUコア数と同じ並列度が最も効率的であるとされています。

ARMシステムにおける並列実行制限の撤廃

-	// Disable parallelism if printing, or if running on
-	// (presumably underpowered) arm systems.
-	if *verbose || runtime.GOARCH == "arm" {
+	// Disable parallelism if printing
+	if *verbose {
 		*numParallel = 1
 	}

このコードブロックは、特定の条件下で並列実行数を1に制限するロジックです。

  • 変更前は、*verbose フラグが設定されている場合(詳細出力モード)または runtime.GOARCH == "arm"(現在の実行アーキテクチャがARMである場合)に、numParallel の値が強制的に1に設定されていました。コメントにあるように、ARMシステムは「おそらく非力」であるという前提がありました。
  • 変更後は、runtime.GOARCH == "arm" の条件が削除されました。これにより、ARMシステム上でも、*verbose フラグが設定されていない限り、numParallel のデフォルト値(またはコマンドラインで指定された値)に基づいてテストが並列実行されるようになります。

この変更は、ARMプロセッサの性能が向上し、もはや「非力」という前提が当てはまらなくなったこと、あるいはGoランタイムがARMシステム上で並列テストを安定して実行できるようになったことを反映しています。これにより、ARMシステム上でのテスト実行時間が短縮され、開発効率が向上することが期待されます。

関連リンク

参考にした情報源リンク

  • 特になし (コミット内容とGo言語の一般的な知識に基づいて解説を生成しました)