[インデックス 18735] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http
パッケージにおける、データ競合検出器(Race Detector)使用時のテストの挙動に関する修正です。具体的には、HeaderWriteSubset
関数のメモリ割り当て(allocations)テストが、Race Detectorが有効な環境下でスキップされるように変更されています。これにより、Race Detectorのオーバーヘッドによるテストの不安定化や誤検出を防ぎ、テストの信頼性を向上させています。
コミット
commit 5f1e0fa538991cf2d2f0f48c8e15a3bca3f52918
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Tue Mar 4 08:56:52 2014 -0800
net/http: disable an alloc test under the race detector
LGTM=dvyukov
R=dvyukov
CC=golang-codereviews
https://golang.org/cl/70200052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5f1e0fa538991cf2d2f0f48c8e15a3bca3f52918
元コミット内容
net/http: disable an alloc test under the race detector
このコミットメッセージは、net/http
パッケージにおいて、メモリ割り当て(allocations)に関するテストを、Goのデータ競合検出器(Race Detector)が有効な場合に無効化することを示しています。
変更の背景
Go言語には、並行処理におけるデータ競合(data race)を検出するための強力なツールである「Race Detector」が組み込まれています。データ競合は、複数のゴルーチンが共有変数に同時にアクセスし、そのうち少なくとも1つが書き込み操作である場合に発生し、予測不能なプログラムの挙動やバグの原因となります。Race Detectorは、コンパイル時に-race
フラグを付与することで有効化され、実行時にメモリアクセスを監視してデータ競合を検出します。
しかし、Race Detectorは、その性質上、実行時にかなりのオーバーヘッドを伴います。メモリ使用量が5〜10倍に増加し、実行時間が2〜20倍に増加する可能性があります。このオーバーヘッドは、特にメモリ割り当ての回数を厳密にチェックするようなパフォーマンス関連のテストにおいて、テスト結果の不安定化や、本来データ競合とは関係のない部分での誤検出を引き起こす可能性があります。
net/http
パッケージの TestHeaderWriteSubsetAllocs
テストは、http.Header
の WriteSubset
メソッドがどれだけメモリを割り当てるかを検証するものです。この種のテストは、非常に厳密なパフォーマンス要件を持つため、Race Detectorのオーバーヘッドがテストの正確性に影響を与える可能性がありました。
このコミットの背景には、Race Detectorが有効な環境下で、このメモリ割り当てテストが期待通りの結果を出さない、あるいは不安定になるという問題があったと考えられます。そのため、Race Detectorが有効な場合にはこのテストをスキップすることで、テストスイート全体の安定性と信頼性を確保することが目的とされています。
前提知識の解説
Go言語のデータ競合(Data Race)
データ競合は、並行プログラミングにおける一般的なバグの一種です。Go言語では、複数のゴルーチン(軽量スレッド)が同じメモリ領域に同時にアクセスし、そのうち少なくとも1つのアクセスが書き込みである場合に発生します。適切な同期メカニズム(ミューテックス、チャネルなど)が使用されていない場合、最終的な値が予測不能になったり、プログラムがクラッシュしたりする可能性があります。
Go Race Detector
Go Race Detectorは、Go 1.1から導入されたデータ競合検出ツールです。go build -race
、go run -race
、go test -race
のように-race
フラグを付けてコンパイル・実行することで有効になります。Race Detectorは、実行時にメモリアクセスを監視し、データ競合が発生した場合には詳細なレポート(競合が発生したゴルーチンのスタックトレース、アクセスタイプ、ソースコード上の位置など)を出力します。これは、C/C++のThreadSanitizerライブラリをベースにしており、動的解析によって競合を検出します。
testing
パッケージとベンチマーク/アロケーションテスト
Go言語の標準ライブラリには、テストを記述するための testing
パッケージが含まれています。
- テスト関数 (
TestXxx
):func TestXxx(t *testing.T)
の形式で記述され、通常の機能テストを行います。 - ベンチマーク関数 (
BenchmarkXxx
):func BenchmarkXxx(b *testing.B)
の形式で記述され、コードのパフォーマンスを測定します。b.N
回の操作にかかる時間を測定したり、b.ReportAllocs()
を呼び出すことで、ベンチマーク実行中のメモリ割り当て回数やバイト数を報告させることができます。 t.Skip()
: テストをスキップするために使用されます。特定の条件(例:testing.Short()
がtrueの場合、特定の環境の場合など)でテストを実行したくない場合に便利です。runtime.GOMAXPROCS(0)
: 現在のGOMAXPROCS
の値(同時に実行できるOSスレッドの最大数)を返します。この値が1より大きい場合、複数のCPUコアが利用可能であり、並行処理のテストにおいて特定の挙動を示す可能性があります。
ビルドタグ(Build Tags)
Go言語では、ソースファイルにビルドタグを記述することで、特定の条件に基づいてファイルをコンパイルに含めるか除外するかを制御できます。ファイル冒頭に // +build tagname
の形式で記述します。このコミットでは // +build race
が使用されており、これはRace Detectorが有効な場合にのみこのファイルがコンパイルされることを意味します。
技術的詳細
このコミットは、Goの net/http
パッケージにおける Header
型の WriteSubset
メソッドのメモリ割り当てテスト TestHeaderWriteSubsetAllocs
が、Race Detectorが有効な場合にスキップされるように修正しています。
具体的な変更点は以下の通りです。
-
src/pkg/net/http/header.go
の変更:var raceEnabled = false // set by race.go
というグローバル変数が追加されました。この変数は、Race Detectorが有効かどうかを示すフラグとして機能します。初期値はfalse
です。
-
src/pkg/net/http/race.go
の新規追加:race.go
という新しいファイルが追加されました。このファイルは、ビルドタグ// +build race
を持っています。これは、Race Detectorが有効なビルドの場合にのみ、このファイルがコンパイルされることを意味します。- このファイルには
init()
関数が含まれており、init()
関数内でraceEnabled = true
が設定されます。 - これにより、Race Detectorが有効なビルドでは
raceEnabled
変数がtrue
に設定され、それ以外のビルドではfalse
のままになります。
-
src/pkg/net/http/header_test.go
の変更:TestHeaderWriteSubsetMallocs
というテスト関数の名前がTestHeaderWriteSubsetAllocs
に変更されました。これは、mallocs
(C言語のメモリ割り当て関数)という用語よりも、Goの文脈でより一般的な「allocs」(割り当て)という用語に合わせたものです。- テストのスキップ条件に
if raceEnabled { t.Skip("skipping test under race detector") }
が追加されました。 - これにより、
raceEnabled
がtrue
(すなわちRace Detectorが有効)の場合、このメモリ割り当てテストは実行されずにスキップされます。 - エラーメッセージも
mallocs = %g; want 0
からallocs = %g; want 0
に変更されています。
この修正により、Race Detectorのオーバーヘッドがメモリ割り当てテストの正確性に影響を与えることを防ぎ、テストスイートの安定性を向上させています。Race Detectorはデータ競合の検出に特化しており、メモリ割り当ての厳密なカウントは本来の目的とは異なるため、このようなテストはRace Detectorの実行時にはスキップするのが適切であるという判断がなされたと考えられます。
コアとなるコードの変更箇所
src/pkg/net/http/header.go
--- a/src/pkg/net/http/header.go
+++ b/src/pkg/net/http/header.go
@@ -13,6 +13,8 @@ import (
"time"
)
+var raceEnabled = false // set by race.go
+
// A Header represents the key-value pairs in an HTTP header.
type Header map[string][]string
src/pkg/net/http/header_test.go
--- a/src/pkg/net/http/header_test.go
+++ b/src/pkg/net/http/header_test.go
@@ -192,9 +192,12 @@ func BenchmarkHeaderWriteSubset(b *testing.B) {
}
}
-func TestHeaderWriteSubsetMallocs(t *testing.T) {
+func TestHeaderWriteSubsetAllocs(t *testing.T) {
if testing.Short() {
-\t\tt.Skip("skipping malloc count in short mode")
+\t\tt.Skip("skipping alloc test in short mode")
+\t}
+\tif raceEnabled {
+\t\tt.Skip("skipping test under race detector")
}
if runtime.GOMAXPROCS(0) > 1 {
t.Skip("skipping; GOMAXPROCS>1")
@@ -204,6 +207,6 @@ func TestHeaderWriteSubsetMallocs(t *testing.T) {
testHeader.WriteSubset(&buf, nil)
})
if n > 0 {
-\t\tt.Errorf("mallocs = %g; want 0", n)
+\t\tt.Errorf("allocs = %g; want 0", n)
}
}
src/pkg/net/http/race.go
(新規追加)
--- /dev/null
+++ b/src/pkg/net/http/race.go
@@ -0,0 +1,11 @@
+// Copyright 2014 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.
+
+// +build race
+
+package http
+
+func init() {
+ raceEnabled = true
+}
コアとなるコードの解説
src/pkg/net/http/header.go
の raceEnabled
変数
var raceEnabled = false
は、net/http
パッケージ全体でRace Detectorが有効かどうかを判断するためのフラグとして機能します。この変数はパッケージレベルで定義されており、他のファイルからアクセス可能です。初期値は false
で、Race Detectorが有効でない通常のビルドではこの値のままです。
src/pkg/net/http/race.go
の init()
関数とビルドタグ
race.go
ファイルは、Goのビルドシステムにおける「ビルドタグ」の典型的な使用例を示しています。
// +build race
という行は、このファイルが go build -race
のように -race
フラグが指定された場合にのみコンパイルされることをGoツールチェインに指示します。
このファイル内の func init() { raceEnabled = true }
は、パッケージが初期化される際に自動的に実行される関数です。したがって、Race Detectorが有効なビルドでは race.go
がコンパイルされ、その init()
関数が実行されることで、header.go
で定義された raceEnabled
変数が true
に設定されます。これにより、net/http
パッケージ内の他のコードがRace Detectorの有効/無効状態をプログラム的にチェックできるようになります。
src/pkg/net/http/header_test.go
の TestHeaderWriteSubsetAllocs
このテスト関数は、http.Header
の WriteSubset
メソッドが、特定の条件下でメモリ割り当てを発生させないことを検証します。
testing.Short()
は、go test -short
フラグが指定された場合に true
を返します。これは、実行時間の長いテストをスキップするための一般的な慣習です。
runtime.GOMAXPROCS(0) > 1
は、Goランタイムが複数のOSスレッドを利用できる場合に true
を返します。これは、並行処理のテストにおいて特定の挙動を考慮する必要がある場合にテストをスキップする条件として使われることがあります。
そして、今回のコミットで追加された if raceEnabled { t.Skip("skipping test under race detector") }
が最も重要な変更点です。前述の race.go
で raceEnabled
が true
に設定されている場合(つまりRace Detectorが有効な場合)、このテストは「Race Detector下でのテストをスキップします」というメッセージと共にスキップされます。
b.ReportAllocs()
はベンチマーク実行中のメモリ割り当てを報告するように設定し、n := testing.AllocsPerRun(100, func() { ... })
は指定された関数を100回実行し、その間の平均メモリ割り当て回数を n
に格納します。このテストでは n
が0であることを期待しており、もし0でなければエラーを報告します。
この一連の変更により、TestHeaderWriteSubsetAllocs
は、Race Detectorが有効な環境では実行されなくなり、テストの安定性と信頼性が向上しました。
関連リンク
- Go Race Detector: https://go.dev/blog/race-detector
- Go Testing Package: https://pkg.go.dev/testing
- Go Build Tags: https://go.dev/cmd/go/#hdr-Build_tags
参考にした情報源リンク
- https://go.dev/blog/race-detector
- https://pkg.go.dev/testing
- https://go.dev/cmd/go/#hdr-Build_tags
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGTWmrVMNTIXABn9Knv4bpdsE4Q1bMqipoOMlDw6qUbj8eXiqZs72VdWEPhb76m56H9EBTUjpJ4HQGAjifDRQKF7Fv94xmXZBR0Wwj3RMZ5aKBcis7Cd0ivDuGo99DCOXbknAaM (Go Race Detectorに関するWeb検索結果)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEPRIn3601ABiN9edJhVZqnv6IfQ2FP_ql0SVGZSudOd76wcbD0SfWtrsk-fqQUT5SPpG6pESL4MgfSm5t-QAE9SKkNmsfqLfrFv4v8z0KZa_sfrbZCutqfX8nId3xpcWU1asv956pt6YiD6UxGc13kY6x915kLuk0DLIbw (Go Race Detectorに関するWeb検索結果)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFUyBwuZwHq83VrW7myKa8H_ICSgUUTUOwl5grT8tWtyYp-Xykwp1lZWBTvYrxJSe6LuTLrlZAOxAxtDt997MWDBpWarZD040ugSlMO2vnX6sX3QrfLQLAgs1oDCnjU8Z20kJNxfatjfnJDlVMm7ENFUDGZ (Go Race Detectorに関するWeb検索結果)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHM6diNEIJ6dqUxu0YSWwhc5xkTWAMbrdN3BDQimYjaS6Q3sd_VVlJVrjfxuopZVarUfDGz9Pn2wbNmcEwvoXhPDKYLGg-iqBcWp82wITRGyXeCIzJh4R4FftCA== (Go Race Detectorに関するWeb検索結果)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGEmUIXC-75DnmkUcEbwNd-bA9nQoa-NV9QhrbubBRKHFkzx5FtpZHKNgMUmLar6SNAGTK3X6K8--gOgTsrKKELXr-6sZKUrlKxGEJxEJczZFr1pJgdAMEqWFd1AZYWaiCHRIAMlPRhjPLZJlfsZPhA71neLnbRLF7kz8QL3TSBkO5bOv4b (Go Race Detectorに関するWeb検索結果)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGRs1mgzUyDOgMy5c0KU393PNdupF0vaBFNKZ-g5udcocjvsgzKSgrxZrd_acV3DAzDKmSViVPfAHEIOcpd5z7P6Q7f_en_SPTNKS7yZnXbve-aPHr4cZd4jpkLsHQsTUVxmOwv6NRYHEUg (Go Race Detectorに関するWeb検索結果)