[インデックス 14995] ファイルの概要
このコミットは、Go言語の標準ライブラリをデータ競合検出器(Race Detector)を用いてテストするためのシェルスクリプト race.bash
を src
ディレクトリに追加するものです。このスクリプトは、適切なハードウェアを持つユーザーがデータ競合検出器を有効にしたビルドを実行し、標準ライブラリのテストを行うことを可能にします。また、Goプロジェクトのダッシュボードビルダーから呼び出されることも想定されています。
コミット
このコミットは、Go言語のソースツリーに race.bash
という新しいシェルスクリプトを追加します。このスクリプトは、Goのデータ競合検出器を使用して標準ライブラリのテストを実行するためのもので、特に linux/amd64
および darwin/amd64
環境でのみサポートされます。スクリプトは、実行環境のOSとアーキテクチャをチェックし、$GOROOT/src
から実行されていることを確認した後、make.bash
を実行し、go install -race std
および go test -race std
コマンドを通じてデータ競合検出器を有効にしたビルドとテストを行います。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b53e95ac2efa287d5932acc4a2dbf68bdb2a5659
元コミット内容
src: add race.bash
Add race.bash so anyone with suitable hardware can run a race detector build. race.bash can be called from the dashboard builder by passing -cmd="race.bash".
Original source for race.bash is here, http://code.google.com/p/go-wiki/wiki/DashboardBuilders
TODO: add race.bat for windows/amd64
R=dvyukov, minux.ma, adg, rsc
CC=fullung, golang-dev
https://golang.org/cl/7179052
変更の背景
この変更の背景には、Go言語の並行処理モデルにおけるデータ競合(data race)の問題を早期に発見し、解決する必要性がありました。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みである場合に発生するバグであり、プログラムの予測不能な動作やクラッシュを引き起こす可能性があります。
Go 1.1から導入されたデータ競合検出器は、このような問題をコンパイル時や実行時に検出するための強力なツールです。しかし、この検出器を有効にしたビルドやテストは、通常のビルドやテストよりも多くのリソース(CPU、メモリ)を消費するため、特定の環境や目的でのみ実行されることが一般的でした。
race.bash
スクリプトの追加は、以下の目的を達成するために行われました。
- データ競合検出器の利用促進: 開発者が自身の環境で簡単にデータ競合検出器を有効にしたビルドとテストを実行できるようにすることで、データ競合バグの早期発見と修正を促します。
- ダッシュボードビルダーとの統合: Goプロジェクトの継続的インテグレーション(CI)システムであるダッシュボードビルダーから
race.bash
を呼び出すことで、自動的にデータ競合検出器を有効にしたテストを実行し、プロジェクト全体の品質を向上させます。これにより、Go標準ライブラリ自体にデータ競合が存在しないことを継続的に保証できるようになります。 - 特定の環境への対応: データ競合検出器が
linux/amd64
とdarwin/amd64
でのみサポートされていたため、これらの環境に特化したスクリプトを提供することで、利用者が適切な環境で確実に検出器を利用できるようにします。
このスクリプトは、Goコミュニティが並行処理の安全性を高めるための継続的な取り組みの一環として追加されました。
前提知識の解説
このコミットとスクリプトを理解するためには、以下の前提知識が必要です。
1. Go言語のデータ競合検出器 (Race Detector)
Go言語のデータ競合検出器は、Go 1.1で導入された強力なツールで、並行処理におけるデータ競合バグを検出します。データ競合は、以下の3つの条件がすべて満たされたときに発生します。
- 少なくとも2つのゴルーチンが同じメモリ位置に同時にアクセスする。
- 少なくとも1つのアクセスが書き込みである。
- アクセスが同期メカニズム(ミューテックス、チャネルなど)によって保護されていない。
データ競合検出器は、プログラムの実行中にメモリアクセスを監視し、上記の条件が満たされた場合に警告を出力します。これにより、開発者は並行処理のバグを特定し、修正することができます。
データ競合検出器を有効にするには、go build
、go run
、go test
コマンドに -race
フラグを追加します。例えば、go test -race ./...
は、現在のモジュール内のすべてのパッケージのテストをデータ競合検出器を有効にして実行します。
2. make.bash
make.bash
は、Go言語のソースコードリポジトリの src
ディレクトリに存在するシェルスクリプトです。これは、Goのツールチェイン全体をビルドするために使用される主要なスクリプトです。GoのソースコードからGoコンパイラ、標準ライブラリ、およびその他のツールを構築する複雑なプロセスを自動化します。
通常、Goのソースコードをクローンした後、cd $GOROOT/src
に移動し、./make.bash
を実行することで、Goのビルド環境をセットアップします。このスクリプトは、Goのビルドシステムの中核をなすものであり、Goのバージョンアップやクロスコンパイル環境の構築など、様々な場面で利用されます。
race.bash
スクリプト内で ./make.bash --no-banner
が呼び出されているのは、データ競合検出器を有効にしたビルドを行う前に、Goのビルド環境が正しく設定されていることを確認し、必要に応じて再構築するためです。--no-banner
オプションは、make.bash
が通常出力するビルド情報のバナーを抑制します。
3. go install -race std
このコマンドは、Goの標準ライブラリ(std
)をデータ競合検出器を有効にしてインストールします。go install
コマンドは、指定されたパッケージをコンパイルし、その結果を $GOPATH/bin
または $GOBIN
に実行可能ファイルとして、または $GOPATH/pkg
にパッケージアーカイブとしてインストールします。
-race
フラグを付けることで、コンパイルされた標準ライブラリのバイナリにデータ競合検出器のランタイムサポートが組み込まれます。これにより、この標準ライブラリを使用するアプリケーションが実行される際に、データ競合が検出されるようになります。
4. go test -race
このコマンドは、指定されたパッケージのテストをデータ競合検出器を有効にして実行します。go test
コマンドは、Goのテストフレームワークを実行するための主要なコマンドです。
race.bash
スクリプトでは、以下の3つの go test -race
コマンドが実行されます。
go test -race -short std
: 標準ライブラリのテストをデータ競合検出器を有効にして実行します。-short
フラグは、時間がかかるテストをスキップし、より迅速なテスト実行を可能にします。go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
: 標準ライブラリのベンチマークテストをデータ競合検出器を有効にして実行します。-run=nothingplease
: 通常のテストは実行せず、ベンチマークのみを実行するためのトリックです。nothingplease
という名前のテスト関数は存在しないため、テストはスキップされます。-bench=.*
: すべてのベンチマークを実行します。-benchtime=.1s
: 各ベンチマークの実行時間を0.1秒に制限します。これにより、ベンチマークテストの実行時間を短縮します。-cpu=4
: ベンチマークテストを4つのCPUコアで並行して実行します。
これらのテストコマンドは、標準ライブラリがデータ競合を起こさないことを確認するために、様々なシナリオでデータ競合検出器を適用しています。
5. シェルスクリプトの基本
#!/usr/bin/env bash
: シバン(shebang)と呼ばれ、このスクリプトがbash
シェルで実行されることを指定します。set -e
: このコマンドは、スクリプト内でエラーが発生した場合(コマンドがゼロ以外の終了ステータスを返した場合)に、スクリプトの実行を即座に終了させるように設定します。これにより、予期せぬエラーが後続の処理に影響を与えるのを防ぎます。function usage { ... }
:usage
という名前の関数を定義します。この関数は、スクリプトの利用方法やエラーメッセージを表示するために使用されます。echo '...' 1>&2
: 標準エラー出力(stderr)にメッセージを出力します。1>&2
は、標準出力(ファイルディスクリプタ1)を標準エラー出力(ファイルディスクリプタ2)にリダイレクトすることを意味します。exit 1
: スクリプトを終了し、終了ステータスとして1を返します。通常、ゼロ以外の終了ステータスはエラーを示します。case $(uname) in ... esac
:uname
コマンドの出力(オペレーティングシステム名)に基づいて条件分岐を行います。Darwin
はmacOS、Linux
はLinuxを指します。sysctl machdep.cpu.extfeatures | grep -qv EM64T
: macOS環境で、CPUがEM64T(Intel 64)をサポートしているかを確認します。sysctl
はシステム情報を取得するコマンド、grep -qv
はパターンに一致しない行を非表示で検索します。[ $(uname -m) != "x86_64" ]
: Linux環境で、CPUアーキテクチャがx86_64
(64ビット)でないことを確認します。[ ! -f make.bash ]
:make.bash
というファイルが存在しないことを確認します。
これらの基本的なシェルスクリプトの知識は、race.bash
の動作を理解するために不可欠です。
技術的詳細
race.bash
スクリプトは、Goのデータ競合検出器を効果的に利用するための堅牢なシェルスクリプトであり、以下の技術的詳細を含んでいます。
1. 環境チェックとエラーハンドリング
スクリプトの冒頭で set -e
が宣言されており、これによりコマンドが失敗した場合(非ゼロの終了コードを返した場合)にスクリプトが即座に終了するようになります。これは、ビルドやテストの途中でエラーが発生した場合に、不完全な結果で処理を続行するのを防ぐための重要な安全策です。
また、usage
関数が定義されており、サポートされていない環境でスクリプトが実行された場合に、適切なエラーメッセージを表示して終了します。
2. OSとアーキテクチャの検証
データ競合検出器は、特定のOSとアーキテクチャの組み合わせでのみサポートされています。race.bash
は、uname
コマンドを使用して現在のOSとアーキテクチャをチェックし、サポートされていない環境であれば usage
関数を呼び出して終了します。
- macOS (Darwin):
sysctl machdep.cpu.extfeatures | grep -qv EM64T
: macOSでは、sysctl
コマンドを使ってCPUの拡張機能を確認し、EM64T
(Intel 64ビットアーキテクチャ)がサポートされていることを確認します。grep -qv EM64T
は、EM64T
が見つからない場合に真となり、その場合はusage
を呼び出します。これは、macOSがIntelベースの64ビットCPUで実行されていることを確認するためのものです。
- Linux:
[ $(uname -m) != "x86_64" ]
: Linuxでは、uname -m
コマンドを使ってマシンアーキテクチャがx86_64
(64ビット)であることを確認します。x86_64
でない場合はusage
を呼び出します。
これらのチェックにより、スクリプトはデータ競合検出器が動作する保証された環境でのみ実行されるようになります。
3. 実行パスの検証
race.bash
は、Goのソースツリーの src
ディレクトリから実行されることを前提としています。これは、make.bash
が同じディレクトリに存在することを期待しているためです。
if [ ! -f make.bash ]; then ... fi
: この条件文は、現在のディレクトリにmake.bash
というファイルが存在しない場合に真となります。その場合、スクリプトはエラーメッセージを出力し、終了します。これにより、ユーザーが誤った場所でスクリプトを実行するのを防ぎます。
4. Goビルド環境の準備
. ./make.bash --no-banner
: この行は、make.bash
スクリプトを現在のシェルでソース(実行)します。これにより、make.bash
が設定する環境変数(例:GOROOT
)がrace.bash
の現在のシェルセッションに引き継がれます。--no-banner
オプションは、make.bash
が通常出力するビルド情報のバナーを抑制し、スクリプトの出力をクリーンに保ちます。このステップは、データ競合検出器を有効にしたビルドを行う前に、Goのビルド環境が正しく設定されていることを保証するために重要です。
5. データ競合検出器を有効にしたビルドとテストの実行
スクリプトの核心部分は、データ競合検出器を有効にしたGoコマンドの実行です。
go install -race std
: Goの標準ライブラリ(std
)をデータ競合検出器を有効にしてコンパイルし、インストールします。これにより、標準ライブラリのバイナリにデータ競合検出器のランタイムサポートが組み込まれ、後続のテストでデータ競合が検出されるようになります。go test -race -short std
: 標準ライブラリのテストをデータ競合検出器を有効にして実行します。-short
フラグは、時間がかかるテストをスキップし、より迅速なテスト実行を可能にします。これは、日常的なCIや開発サイクルでの利用に適しています。go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
: 標準ライブラリのベンチマークテストをデータ競合検出器を有効にして実行します。-run=nothingplease
: 存在しないテスト名を指定することで、通常のテストの実行をスキップします。-bench=.*
: すべてのベンチマークを実行対象とします。-benchtime=.1s
: 各ベンチマークの実行時間を0.1秒に制限します。これにより、ベンチマークテストの実行時間を短縮し、CI環境での実行に適した時間で完了させます。-cpu=4
: ベンチマークテストを4つのCPUコアで並行して実行します。これにより、並行処理のシナリオでのデータ競合の検出可能性を高めます。
これらのコマンドの組み合わせにより、race.bash
はGo標準ライブラリのデータ競合を包括的にテストし、潜在的な問題を特定するための強力なメカニズムを提供します。
コアとなるコードの変更箇所
このコミットによるコアとなるコードの変更箇所は、src/race.bash
という新しいファイルが追加されたことです。
--- /dev/null
+++ b/src/race.bash
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# Copyright 2013 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# race.bash tests the standard library under the race detector.
+# http://golang.org/doc/articles/race_detector.html
+
+set -e
+
+function usage {
+ echo 'race detector is only supported on linux/amd64 and darwin/amd64' 1>&2
+ exit 1
+}
+
+case $(uname) in
+"Darwin")
+ # why Apple? why?
+ if sysctl machdep.cpu.extfeatures | grep -qv EM64T; then
+ usage
+ fi
+ ;;
+"Linux")
+ if [ $(uname -m) != "x86_64" ]; then
+ usage
+ fi
+ ;;
+*)
+ usage
+ ;;
+esac
+
+if [ ! -f make.bash ]; then
+ echo 'race.bash must be run from $GOROOT/src' 1>&2
+ exit 1
+fi
+. ./make.bash --no-banner
+go install -race std
+go test -race -short std
+go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
このファイルは、実行可能スクリプトとして 100755
のパーミッションで追加されています。
コアとなるコードの解説
src/race.bash
スクリプトの各セクションを詳細に解説します。
#!/usr/bin/env bash
# Copyright 2013 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# race.bash tests the standard library under the race detector.
# http://golang.org/doc/articles/race_detector.html
- シバン:
#!/usr/bin/env bash
は、このスクリプトがbash
シェルで実行されることを指定します。env
を使用することで、bash
のパスが環境変数PATH
から解決されるため、システムごとのbash
のインストールパスの違いを吸収できます。 - 著作権表示とライセンス: Goプロジェクトの標準的な著作権表示とBSDスタイルのライセンスに関するコメントです。
- スクリプトの目的:
race.bash tests the standard library under the race detector.
というコメントは、このスクリプトの主要な目的が、データ競合検出器を使用してGo標準ライブラリをテストすることであることを明確に示しています。 - 関連ドキュメントへのリンク:
http://golang.org/doc/articles/race_detector.html
は、Goのデータ競合検出器に関する公式ドキュメントへのリンクであり、ユーザーが詳細情報を参照できるようにしています。
set -e
- エラー時の終了:
set -e
は、スクリプト内で実行されるコマンドが非ゼロの終了ステータスを返した場合(つまりエラーが発生した場合)に、スクリプトの実行を即座に終了させるように設定します。これにより、エラーが発生したにもかかわらずスクリプトが続行し、予期せぬ結果を引き起こすことを防ぎます。
function usage {
echo 'race detector is only supported on linux/amd64 and darwin/amd64' 1>&2
exit 1
}
usage
関数: この関数は、スクリプトがサポートされていない環境で実行された場合に呼び出されます。echo '...' 1>&2
: データ競合検出器がlinux/amd64
とdarwin/amd64
でのみサポートされていることを示すエラーメッセージを標準エラー出力(1>&2
)に出力します。exit 1
: スクリプトを終了し、エラーを示す終了ステータス1
を返します。
case $(uname) in
"Darwin")
# why Apple? why?
if sysctl machdep.cpu.extfeatures | grep -qv EM64T; then
usage
fi
;;
"Linux")
if [ $(uname -m) != "x86_64" ]; then
usage
fi
;;
*)
usage
;;
esac
- OSとアーキテクチャのチェック: この
case
ステートメントは、uname
コマンドの出力(オペレーティングシステム名)に基づいて、スクリプトがサポートされている環境で実行されているかを確認します。"Darwin"
(macOS):sysctl machdep.cpu.extfeatures | grep -qv EM64T
:sysctl
コマンドでCPUの拡張機能を取得し、grep -qv EM64T
でEM64T
(Intel 64ビットアーキテクチャ)が存在しない場合に真となります。これは、macOSがIntelベースの64ビットCPUで実行されていることを確認するためのものです。もし条件が真であれば、usage
関数が呼び出されます。
"Linux"
:[ $(uname -m) != "x86_64" ]
:uname -m
コマンドでマシンアーキテクチャを取得し、それがx86_64
(64ビット)でない場合に真となります。もし条件が真であれば、usage
関数が呼び出されます。
*
: 上記のどのケースにも一致しない場合(サポートされていないOSの場合)は、usage
関数が呼び出されます。
if [ ! -f make.bash ]; then
echo 'race.bash must be run from $GOROOT/src' 1>&2
exit 1
fi
- 実行パスの検証: この
if
ステートメントは、スクリプトがGoのソースツリーのsrc
ディレクトリから実行されていることを確認します。[ ! -f make.bash ]
: 現在のディレクトリにmake.bash
というファイルが存在しない場合に真となります。- もし条件が真であれば、
race.bash must be run from $GOROOT/src
というエラーメッセージを標準エラー出力に出力し、終了ステータス1
でスクリプトを終了します。これは、make.bash
がGoのビルドプロセスにおいて重要な役割を果たすため、その存在が前提となっているためです。
. ./make.bash --no-banner
- Goビルド環境の初期化: この行は、
make.bash
スクリプトを現在のシェルでソース(実行)します。.
(ドットコマンド): スクリプトを現在のシェル環境で実行することを意味します。これにより、make.bash
が設定する環境変数(例:GOROOT
)や関数が、race.bash
の現在のシェルセッションに引き継がれます。./make.bash
: 現在のディレクトリにあるmake.bash
スクリプトを指定します。--no-banner
:make.bash
が通常出力するビルド情報のバナーを抑制するオプションです。これにより、スクリプトの出力がより簡潔になります。このステップは、データ競合検出器を有効にしたビルドを行う前に、Goのビルド環境が正しく設定されていることを保証するために不可欠です。
go install -race std
go test -race -short std
go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
- データ競合検出器を有効にしたビルドとテスト: これらはスクリプトの主要な実行コマンドです。
go install -race std
: Goの標準ライブラリ(std
)をデータ競合検出器を有効にしてコンパイルし、インストールします。これにより、標準ライブラリのバイナリにデータ競合検出器のランタイムサポートが組み込まれます。go test -race -short std
: 標準ライブラリのテストをデータ競合検出器を有効にして実行します。-short
フラグは、時間がかかるテストをスキップし、より迅速なテスト実行を可能にします。go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
: 標準ライブラリのベンチマークテストをデータ競合検出器を有効にして実行します。-run=nothingplease
: 存在しないテスト名を指定することで、通常のテストの実行をスキップし、ベンチマークのみを実行します。-bench=.*
: すべてのベンチマークを実行対象とします。-benchtime=.1s
: 各ベンチマークの実行時間を0.1秒に制限します。-cpu=4
: ベンチマークテストを4つのCPUコアで並行して実行します。
これらのコマンドは、Go標準ライブラリがデータ競合を起こさないことを確認するために、様々なシナリオでデータ競合検出器を適用し、包括的なテストカバレッジを提供します。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/b53e95ac2efa287d5932acc4a2dbf68bdb2a5659
- Goデータ競合検出器に関する公式ドキュメント: http://golang.org/doc/articles/race_detector.html
- Go Wiki - DashboardBuilders (元のソース): http://code.google.com/p/go-wiki/wiki/DashboardBuilders
- Go CL (Change List) 7179052: https://golang.org/cl/7179052
参考にした情報源リンク
- Go公式ドキュメント: https://golang.org/doc/
- Go Wiki: https://go.dev/wiki/
go build
コマンドのドキュメント: https://pkg.go.dev/cmd/go#hdr-Build_packages_and_dependenciesgo test
コマンドのドキュメント: https://pkg.go.dev/cmd/go#hdr-Test_packagesgo install
コマンドのドキュメント: https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies- Bashスクリプトの基本(
set -e
,case
,function
など)に関する一般的な情報源。 uname
コマンドのドキュメント。sysctl
コマンドのドキュメント。grep
コマンドのドキュメント。test
コマンド([
)のドキュメント。- Goのビルドシステムに関する一般的な情報源。
- Goの継続的インテグレーション(CI)システムに関する一般的な情報源。
- データ競合に関する一般的なコンピュータサイエンスの概念。