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

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

このコミットは、Go言語の標準ライブラリに対してデータ競合検出器(Race Detector)を実行するためのWindowsバッチスクリプト race.bat を追加するものです。これにより、Windows環境においてもGoの並行処理における潜在的なバグ(データ競合)を効率的に特定できるようになります。

コミット

commit 8047e8e95a917f44ed0b12a0a382a6b144a8797f
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Sun Feb 3 00:49:37 2013 +0800

    src: add race.bat
    
    R=golang-dev, dave, alex.brainman
    CC=golang-dev
    https://golang.org/cl/7133064

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

https://github.com/golang/go/commit/8047e8e95a917f44ed0b12a0a382a6b144a8797f

元コミット内容

src: add race.bat

R=golang-dev, dave, alex.brainman
CC=golang-dev
https://golang.org/cl/7133064

変更の背景

Go言語は並行処理を強力にサポートしており、ゴルーチン(goroutine)とチャネル(channel)を用いることで、並行プログラムを容易に記述できます。しかし、並行処理はデータ競合(data race)という種類のバグを引き起こす可能性があります。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生します。このような競合は、プログラムの予測不能な動作、クラッシュ、または誤った結果につながる可能性があり、デバッグが非常に困難です。

Go 1.1から導入されたRace Detectorは、実行時にデータ競合を検出するための強力なツールです。このツールは、プログラムの実行を監視し、データ競合のパターンを特定すると、詳細なレポート(競合が発生した場所、関連するスタックトレースなど)を出力します。

このコミットの背景には、Goの標準ライブラリ自体がデータ競合を含んでいないことを保証するためのテストインフラの拡充があります。特に、Windows環境での開発者やCI/CDパイプラインがRace Detectorを容易に利用できるように、プラットフォーム固有のスクリプト(race.bat)が必要とされました。これにより、Goのクロスプラットフォームな品質保証体制が強化されます。

前提知識の解説

データ競合 (Data Race)

データ競合は、並行プログラミングにおける最も一般的なバグの一つです。Go言語の文脈では、以下の3つの条件がすべて満たされた場合にデータ競合が発生します。

  1. 複数のゴルーチンからのアクセス: 2つ以上のゴルーチンが同じメモリ位置にアクセスする。
  2. 少なくとも1つの書き込み: アクセスのうち少なくとも1つが書き込み操作である。
  3. 同期メカニズムの欠如: これらのアクセスが、ミューテックス(sync.Mutex)やチャネル(chan)などの同期メカニズムによって適切に保護されていない。

データ競合が発生すると、プログラムの実行順序が非決定論的になり、結果としてプログラムの動作が予測不能になります。これは「未定義動作」の一種であり、デバッグが非常に困難なため、Race Detectorのようなツールが不可欠です。

Go Race Detector

Go Race Detectorは、Go 1.1で導入された動的解析ツールです。これは、コンパイル時に-raceフラグをgo buildgo rungo testコマンドに渡すことで有効になります。

go build -race myprogram.go
go test -race mypackage

Race Detectorが有効な状態でプログラムを実行すると、メモリへのアクセス(読み書き)と同期イベント(ミューテックスのロック/アンロック、チャネル操作など)が監視されます。データ競合が検出されると、Race Detectorは以下のような詳細なレポートを標準エラー出力に表示します。

  • 競合が発生したメモリ位置
  • 競合に関与した各ゴルーチンのスタックトレース
  • 競合に関与したメモリ操作の種類(読み込みまたは書き込み)

Race Detectorは、GoogleのSanitizersプロジェクトの一部であるThreadSanitizerをベースにしており、実行時のオーバーヘッドはありますが、データ競合の検出において非常に効果的です。

Windowsバッチスクリプト (.bat)

Windowsバッチスクリプトは、Windowsコマンドプロンプト(cmd.exe)で実行される一連のコマンドを記述したテキストファイルです。.batまたは.cmd拡張子を持ちます。このスクリプトは、Goのビルドプロセスやテスト実行を自動化するために使用されます。

  • @echo off: コマンドの実行結果を非表示にする。
  • setlocal: 環境変数の変更をスクリプトの実行範囲に限定する。
  • if exist: ファイルやディレクトリの存在を確認する。
  • goto: 指定されたラベルにジャンプする。
  • call: 別のバッチスクリプトを実行する。
  • %VAR%: 環境変数の値にアクセスする。
  • errorlevel: 直前のコマンドの終了コード(0は成功、非0は失敗)を示す。

技術的詳細

src/race.batスクリプトは、Goの標準ライブラリに対してRace Detectorを有効にした状態でビルドおよびテストを実行するための一連のステップを自動化します。

  1. 環境チェック:

    • スクリプトがGoのソースディレクトリ(go\src)から実行されていることを確認するために、make.batファイルの存在をチェックします。これは、Goのビルドシステムが特定のディレクトリ構造に依存しているためです。
    • setlocalコマンドにより、スクリプト内で設定される環境変数がスクリプトの終了時に自動的に元に戻るようにします。
  2. ビルド環境の準備:

    • call make.bat --dist-tool >NUL: Goのビルドツール(dist)をビルドします。>NULは標準出力を抑制します。
    • .\\cmd\\dist\\dist env -wp >env.bat: dist env -wpコマンドを実行し、Goのビルドに必要な環境変数(GOROOT, GOPATH, GOBINなど)をenv.batという一時ファイルに書き出します。-wpフラグは、Windowsパス形式で環境変数を設定することを意味します。
    • call env.bat: 生成されたenv.batを実行し、現在のシェルセッションにGoのビルド環境変数を設定します。
    • del env.bat: 一時ファイルenv.batを削除します。
  3. Race Detectorのサポート確認:

    • if %GOHOSTARCH% == amd64 goto continue: Race Detectorは、当時のGo 1.1の時点ではWindows/amd64アーキテクチャでのみサポートされていました。それ以外のアーキテクチャで実行された場合はエラーメッセージを表示し、スクリプトを終了します。
  4. 標準ライブラリのビルドとテスト:

    • call make.bat --no-banner --no-local: Goの標準ライブラリをビルドします。--no-banner--no-localは、ビルド時の出力とローカル環境への影響を抑制するためのオプションです。
    • go install -race std: Race Detectorを有効にして、Goの標準ライブラリ(std)をインストール(ビルド)します。これにより、標準ライブラリの各パッケージがRace Detectorのインストゥルメンテーション(計測コードの埋め込み)を伴ってコンパイルされます。
    • go test -race -short -std: Race Detectorを有効にして、標準ライブラリのテストを実行します。-shortフラグは、時間がかかるテストをスキップし、迅速な実行を可能にします。
    • go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std: Race Detectorを有効にして、標準ライブラリのベンチマークテストを実行します。
      • -run=nothingplease: 通常のテストは実行せず、ベンチマークのみを実行するための正規表現パターン。
      • -bench=.*: すべてのベンチマークを実行する。
      • -benchtime=.1s: 各ベンチマークの実行時間を0.1秒に制限する。
      • -cpu=4: ベンチマークを4つのCPUコアで並行して実行する。
  5. エラーハンドリング:

    • 各コマンドの実行後、if errorlevel 1 goto failでエラーレベルをチェックし、エラーが発生した場合はfailラベルにジャンプしてスクリプトを終了します。
    • GOBUILDFAIL環境変数を使用して、ビルドまたはテストが失敗したかどうかを追跡します。

このスクリプトは、GoのビルドシステムとRace Detectorの機能を組み合わせて、Windows環境でのデータ競合検出を自動化する典型的な例です。

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

このコミットでは、src/race.batという新しいファイルが追加されています。

--- /dev/null
+++ b/src/race.bat
@@ -0,0 +1,52 @@
+:: 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
+
+@echo off
+
+setlocal
+
+if exist make.bat goto ok
+echo race.bat must be run from go\src
+:: cannot exit: would kill parent command interpreter
+goto end
+:ok
+
+call make.bat --dist-tool >NUL
+if errorlevel 1 goto fail
+.\\cmd\\dist\\dist env -wp >env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+
+if %GOHOSTARCH% == amd64 goto continue
+echo Race detector is only supported on windows/amd64.
+goto fail
+
+:continue
+call make.bat --no-banner --no-local
+if %GOBUILDFAIL%==1 goto end
+echo # go install -race std
+go install -race std
+if errorlevel 1 goto fail
+echo # go test -race -short -std
+go test -race -short std
+if errorlevel 1 goto fail
+echo # go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
+go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
+if errorlevel 1 goto fail
+goto succ
+
+:fail
+set GOBUILDFAIL=1
+echo Fail.
+goto end
+
+:succ
+echo All tests passed.
+
+:end

コアとなるコードの解説

追加されたrace.batスクリプトは、Goの標準ライブラリに対してRace Detectorを適用し、データ競合の有無を検証するための自動化されたワークフローを提供します。

スクリプトの主要な部分は以下の通りです。

  1. 初期チェックと環境設定:

    • if exist make.bat goto ok: スクリプトがGoのソースツリーのルート(srcディレクトリ)から実行されていることを確認します。これは、make.batがそのディレクトリに存在するためです。
    • call make.bat --dist-tool >NUL: Goの内部ビルドツールであるdistコマンドをビルドします。これは、Goのビルドプロセスを制御するための重要なツールです。
    • .\\cmd\\dist\\dist env -wp >env.batcall env.bat: dist env -wpコマンドは、Goのビルドに必要な環境変数(GOROOT, GOPATHなど)を一時的なバッチファイルenv.batに書き出し、それを実行することで現在のシェルセッションにGoのビルド環境を設定します。これにより、goコマンドが正しく動作するためのパスが設定されます。
  2. アーキテクチャの確認:

    • if %GOHOSTARCH% == amd64 goto continue: 当時、Go Race DetectorはWindows環境ではamd64アーキテクチャのみをサポートしていました。このチェックにより、サポートされていないアーキテクチャでの実行を早期に終了させ、適切なエラーメッセージを表示します。
  3. Race Detectorによるビルドとテスト:

    • go install -race std: Goの標準ライブラリ全体をRace Detectorを有効にしてビルドし、インストールします。-raceフラグは、コンパイルされたバイナリにデータ競合検出のためのインストゥルメンテーションコードを埋め込みます。
    • go test -race -short std: Race Detectorを有効にして、標準ライブラリのユニットテストを実行します。-shortフラグは、実行時間の長いテストをスキップし、迅速なフィードバックを提供します。
    • go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std: Race Detectorを有効にして、標準ライブラリのベンチマークテストを実行します。ベンチマークテストも並行処理を多用するため、データ競合の検出に適しています。-run=nothingpleaseは通常のテストを実行しないようにし、-bench=.*はすべてのベンチマークを実行します。-benchtime-cpuはベンチマークの実行設定です。
  4. 結果の報告:

    • goコマンドの実行後、errorlevel(直前のコマンドの終了コード)をチェックし、エラーが発生した場合はfailラベルにジャンプして「Fail.」と表示します。
    • すべてのテストが成功した場合は、「All tests passed.」と表示されます。

このスクリプトは、GoのビルドシステムとRace Detectorの機能をWindowsバッチスクリプトとして統合し、Go標準ライブラリの品質保証プロセスに不可欠な役割を果たしています。

関連リンク

参考にした情報源リンク

  • Go Race Detectorの公式ドキュメント
  • Go言語のソースコードとコミット履歴
  • Windowsバッチスクリプトに関する一般的な情報