[インデックス 14147] ファイルの概要
このコミットは、Go言語のランタイムにおけるメモリ割り当て処理、特にruntime·new
関数に、データ競合検出器(Race Detector)が有効な場合にのみm->racepc
を設定する条件分岐を追加するものです。これにより、Race Detectorが有効でない場合の不要な処理を削減し、パフォーマンスの最適化とコードの正確性を向上させています。
コミット
commit 6273c7324fa671f8e8e43c0113e842d2ab5fe8b9
Author: Dmitriy Vyukov <dvyukov@google.com>
Date: Mon Oct 15 13:54:31 2012 +0400
runtime: add missing if(raceenabled)
R=0xe2.0x9a.0x9b, minux.ma, iant, dave
CC=golang-dev
https://golang.org/cl/6654052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6273c7324fa671f8e8e43c0113e842d2ab5fe8b9
元コミット内容
runtime: add missing if(raceenabled)
変更の背景
この変更は、Go言語のランタイムにおけるデータ競合検出器(Race Detector)の挙動に関連しています。GoのRace Detectorは、並行処理におけるデータ競合(複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも一方が書き込み操作である場合に発生するバグ)を検出するための強力なツールです。
runtime·new
関数は、Goの組み込み関数new
に対応するランタイム側の実装であり、新しいメモリ領域を割り当ててゼロ初期化を行います。Race Detectorが有効な場合、メモリ割り当ての際に、その割り当てが行われたプログラムカウンタ(PC)情報を記録することがあります。これは、競合が発生した際に、どのコードがメモリにアクセスしたかを特定するために重要です。
しかし、Race Detectorが有効でない場合(つまり、raceenabled
フラグがfalse
の場合)、このPC情報を記録する処理は不要であり、オーバーヘッドとなります。このコミット以前は、raceenabled
のチェックなしに常にm->racepc = runtime·getcallerpc(&typ);
が実行されていました。これは、Race Detectorが有効でないビルドにおいても、不要な命令実行とレジスタへの書き込みが発生することを意味します。
このコミットの目的は、この不要な処理を排除し、Race Detectorが無効な場合のランタイムのパフォーマンスをわずかに向上させることにあります。これは、Goランタイムの継続的な最適化の一環であり、細かなパフォーマンス改善が全体の効率に寄与するという哲学に基づいています。
前提知識の解説
Go言語のランタイム (Runtime)
Go言語のランタイムは、Goプログラムの実行を管理する低レベルのシステムです。これには、ガベージコレクション、スケジューラ(ゴルーチンの管理)、メモリ割り当て、システムコールインターフェースなどが含まれます。Goプログラムは、コンパイル時にランタイムとリンクされ、自己完結型のバイナリを生成します。src/pkg/runtime
ディレクトリには、これらのランタイムのコアコンポーネントのソースコードが含まれています。
データ競合検出器 (Race Detector)
Goのデータ競合検出器は、Go 1.1で導入された機能で、並行プログラムにおけるデータ競合を動的に検出します。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、そのうち少なくとも1つが書き込み操作である場合に発生します。これは、プログラムの予測不能な動作やバグの原因となります。Race Detectorは、プログラムの実行中にメモリアクセスを監視し、競合パターンを検出すると警告を出力します。これは、go run -race
、go build -race
、go test -race
などのコマンドで有効にできます。
mallocgc
runtime·mallocgc
は、Goランタイムにおける主要なメモリ割り当て関数の一つです。これは、ガベージコレクタによって管理されるヒープメモリから新しいメモリブロックを割り当てます。mallocgc
は、割り当てられたメモリをゼロ初期化し、ガベージコレクタがそのメモリを追跡できるように必要なメタデータを設定します。
runtime·getcallerpc
runtime·getcallerpc
は、現在の関数の呼び出し元のプログラムカウンタ(PC)を取得するランタイム関数です。PCは、実行中の命令のアドレスを示すレジスタであり、デバッグやプロファイリング、そしてRace Detectorのようなツールがコードの実行パスを追跡するために使用されます。この関数は、通常、スタックフレームを遡って呼び出し元のPCを特定します。
raceenabled
raceenabled
は、Goランタイム内部で使用されるグローバルなブール型変数です。この変数は、プログラムがRace Detectorを有効にしてビルドされたかどうかを示します。raceenabled
がtrue
の場合、Race Detector関連の追加の監視および記録ロジックが実行されます。false
の場合、これらのロジックはスキップされ、パフォーマンスのオーバーヘッドが削減されます。
m->racepc
m
は、Goランタイムにおけるm
構造体(runtime.m
)を指すことが多いです。これは、OSのスレッドを表す構造体であり、ゴルーチンの実行、スタック管理、スケジューリングなど、スレッド固有の情報を保持します。m->racepc
は、このm
構造体内のフィールドで、Race Detectorが有効な場合に、メモリ割り当てが行われた時点のプログラムカウンタを記録するために使用されます。これにより、競合が発生した際に、どのスレッド(およびそのスレッドが実行していたゴルーチン)が問題のメモリにアクセスしたかを特定する手助けとなります。
KindNoPointers
と FlagNoPointers
Goの型システムでは、各型がポインタを含むかどうかを示す情報を持っています。KindNoPointers
は、特定の型がポインタを含まないことを示すフラグです。runtime·new
関数では、割り当てるメモリがポインタを含まない場合、FlagNoPointers
というフラグをmallocgc
に渡します。これは、ガベージコレクタがポインタを含まないメモリ領域をスキャンする必要がないことを示し、ガベージコレクションの効率を向上させます。
技術的詳細
このコミットは、src/pkg/runtime/malloc.goc
ファイル内のruntime·new
関数に対する変更です。malloc.goc
は、Goランタイムのメモリ割り当てに関するC言語(Goのランタイムは一部C言語で記述されています)のソースファイルです。
変更前は、runtime·new
関数内で、m->racepc = runtime·getcallerpc(&typ);
という行が常に実行されていました。この行は、現在の呼び出し元のプログラムカウンタを取得し、それを現在のOSスレッド(m
)のracepc
フィールドに設定します。この操作は、Race Detectorが有効な場合にのみ意味を持ちます。
変更後は、この行がif(raceenabled)
という条件文で囲まれています。
if(raceenabled)
m->racepc = runtime·getcallerpc(&typ);
これにより、raceenabled
がtrue
(つまり、Race Detectorが有効)の場合にのみ、runtime·getcallerpc
の呼び出しとm->racepc
への代入が行われるようになります。raceenabled
がfalse
の場合、このブロックはスキップされ、不要な処理が実行されなくなります。
この変更は、特にRace Detectorを無効にしてビルドされたGoプログラムにおいて、わずかながらもパフォーマンス上の利益をもたらします。runtime·getcallerpc
はスタックを遡る操作を伴うため、それなりのコストがかかる可能性があります。このコストを不要な場合に回避することで、全体的なランタイムの効率が向上します。
コアとなるコードの変更箇所
変更はsrc/pkg/runtime/malloc.goc
ファイル内のruntime·new
関数にあります。
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -693,7 +693,8 @@ runtime·new(Type *typ, uint8 *ret)
{
uint32 flag;
- m->racepc = runtime·getcallerpc(&typ);
+ if(raceenabled)
+ m->racepc = runtime·getcallerpc(&typ);
flag = typ->kind&KindNoPointers ? FlagNoPointers : 0;
ret = runtime·mallocgc(typ->size, flag, 1, 1);
コアとなるコードの解説
runtime·new
関数は、Goのnew
組み込み関数が呼び出されたときに、ランタイムが新しいメモリを割り当てるために使用する内部関数です。
uint32 flag;
:メモリ割り当てに関するフラグを保持するための変数です。- 変更前の行:
m->racepc = runtime·getcallerpc(&typ);
この行は、Race Detectorが有効かどうかにかかわらず、常に実行されていました。runtime·getcallerpc(&typ)
は、runtime·new
を呼び出した関数のプログラムカウンタを取得し、それを現在のスレッド(m
)のracepc
フィールドに格納します。 - 変更後の行:
この変更により、if(raceenabled) m->racepc = runtime·getcallerpc(&typ);
m->racepc
への代入とruntime·getcallerpc
の呼び出しは、グローバル変数raceenabled
がtrue
の場合にのみ実行されるようになりました。raceenabled
は、GoプログラムがRace Detectorを有効にしてビルドされた場合にtrue
になります。これにより、Race Detectorが無効なビルドでは、この処理が完全にスキップされ、不要なオーバーヘッドが削減されます。 flag = typ->kind&KindNoPointers ? FlagNoPointers : 0;
:割り当てる型typ
がポインタを含まない型であるかどうかをチェックし、それに応じてFlagNoPointers
フラグを設定します。このフラグは、ガベージコレクタがメモリをスキャンする際のヒントとしてmallocgc
に渡されます。ret = runtime·mallocgc(typ->size, flag, 1, 1);
:実際にメモリを割り当てる関数です。typ->size
は割り当てるメモリのサイズ、flag
は上記で設定されたフラグ、残りの引数はガベージコレクションに関する内部的な情報です。
このコミットは、Goランタイムの細部にわたる最適化の一例であり、特定の機能(Race Detector)が有効な場合にのみ関連するコードパスを実行することで、全体的な効率を高めることを目的としています。
関連リンク
- Go言語のデータ競合検出器に関する公式ドキュメント:
- Go言語のランタイムソースコード(GitHub):
- このコミットが属するGoの変更リスト(CL):
参考にした情報源リンク
- The Go Race Detector - The Go Programming Language
- Go runtime source code on GitHub
- Go issue tracker and code review system (Gerrit)
- Go's memory allocator: Malloc and the TCMalloc algorithm (直接の参照ではないが、
mallocgc
の背景理解に役立つ) - Go's runtime scheduler (直接の参照ではないが、
m
構造体の背景理解に役立つ) - Go's garbage collector (直接の参照ではないが、
mallocgc
の背景理解に役立つ) - Go's type system and reflection (直接の参照ではないが、
Type
やKindNoPointers
の背景理解に役立つ) - Program counter - Wikipedia
- Call stack - Wikipedia
- Go runtime internals (various blog posts and talks) (一般的なGoランタイムの理解に役立つ)
- Go's runtime source code comments (Goのソースコード内のコメントは非常に詳細で参考になる)
- Go's runtime documentation (Goの標準ライブラリのドキュメント)
- Go's internal documentation (e.g.,
src/runtime/README
) (Goランタイムの内部構造に関する情報) - Go's
new
built-in function documentation# [インデックス 14147] ファイルの概要
このコミットは、Go言語のランタイムにおけるメモリ割り当て処理、特にruntime·new
関数に、データ競合検出器(Race Detector)が有効な場合にのみm->racepc
を設定する条件分岐を追加するものです。これにより、Race Detectorが有効でない場合の不要な処理を削減し、パフォーマンスの最適化とコードの正確性を向上させています。
コミット
commit 6273c7324fa671f8e8e43c0113e842d2ab5fe8b9
Author: Dmitriy Vyukov <dvyukov@google.com>
Date: Mon Oct 15 13:54:31 2012 +0400
runtime: add missing if(raceenabled)
R=0xe2.0x9a.0x9b, minux.ma, iant, dave
CC=golang-dev
https://golang.org/cl/6654052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6273c7324fa671f8e8e43c0113e842d2ab5fe8b9
元コミット内容
runtime: add missing if(raceenabled)
変更の背景
この変更は、Go言語のランタイムにおけるデータ競合検出器(Race Detector)の挙動に関連しています。GoのRace Detectorは、並行処理におけるデータ競合(複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも一方が書き込み操作である場合に発生するバグ)を検出するための強力なツールです。
runtime·new
関数は、Goの組み込み関数new
に対応するランタイム側の実装であり、新しいメモリ領域を割り当ててゼロ初期化を行います。Race Detectorが有効な場合、メモリ割り当ての際に、その割り当てが行われたプログラムカウンタ(PC)情報を記録することがあります。これは、競合が発生した際に、どのコードがメモリにアクセスしたかを特定するために重要です。
しかし、Race Detectorが有効でない場合(つまり、raceenabled
フラグがfalse
の場合)、このPC情報を記録する処理は不要であり、オーバーヘッドとなります。このコミット以前は、raceenabled
のチェックなしに常にm->racepc = runtime·getcallerpc(&typ);
が実行されていました。これは、Race Detectorが有効でないビルドにおいても、不要な命令実行とレジスタへの書き込みが発生することを意味します。
このコミットの目的は、この不要な処理を排除し、Race Detectorが無効な場合のランタイムのパフォーマンスをわずかに向上させることにあります。これは、Goランタイムの継続的な最適化の一環であり、細かなパフォーマンス改善が全体の効率に寄与するという哲学に基づいています。
前提知識の解説
Go言語のランタイム (Runtime)
Go言語のランタイムは、Goプログラムの実行を管理する低レベルのシステムです。これには、ガベージコレクション、スケジューラ(ゴルーチンの管理)、メモリ割り当て、システムコールインターフェースなどが含まれます。Goプログラムは、コンパイル時にランタイムとリンクされ、自己完結型のバイナリを生成します。src/pkg/runtime
ディレクトリには、これらのランタイムのコアコンポーネントのソースコードが含まれています。
データ競合検出器 (Race Detector)
Goのデータ競合検出器は、Go 1.1で導入された機能で、並行プログラムにおけるデータ競合を動的に検出します。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、そのうち少なくとも1つが書き込み操作である場合に発生します。これは、プログラムの予測不能な動作やバグの原因となります。Race Detectorは、プログラムの実行中にメモリアクセスを監視し、競合パターンを検出すると警告を出力します。これは、go run -race
、go build -race
、go test -race
などのコマンドで有効にできます。
mallocgc
runtime·mallocgc
は、Goランタイムにおける主要なメモリ割り当て関数の一つです。これは、ガベージコレクタによって管理されるヒープメモリから新しいメモリブロックを割り当てます。mallocgc
は、割り当てられたメモリをゼロ初期化し、ガベージコレクタがそのメモリを追跡できるように必要なメタデータを設定します。
runtime·getcallerpc
runtime·getcallerpc
は、現在の関数の呼び出し元のプログラムカウンタ(PC)を取得するランタイム関数です。PCは、実行中の命令のアドレスを示すレジスタであり、デバッグやプロファイリング、そしてRace Detectorのようなツールがコードの実行パスを追跡するために使用されます。この関数は、通常、スタックフレームを遡って呼び出し元のPCを特定します。
raceenabled
raceenabled
は、Goランタイム内部で使用されるグローバルなブール型変数です。この変数は、プログラムがRace Detectorを有効にしてビルドされたかどうかを示します。raceenabled
がtrue
の場合、Race Detector関連の追加の監視および記録ロジックが実行されます。false
の場合、これらのロジックはスキップされ、パフォーマンスのオーバーヘッドが削減されます。
m->racepc
m
は、Goランタイムにおけるm
構造体(runtime.m
)を指すことが多いです。これは、OSのスレッドを表す構造体であり、ゴルーチンの実行、スタック管理、スケジューリングなど、スレッド固有の情報を保持します。m->racepc
は、このm
構造体内のフィールドで、Race Detectorが有効な場合に、メモリ割り当てが行われた時点のプログラムカウンタを記録するために使用されます。これにより、競合が発生した際に、どのスレッド(およびそのスレッドが実行していたゴルーチン)が問題のメモリにアクセスしたかを特定する手助けとなります。
KindNoPointers
と FlagNoPointers
Goの型システムでは、各型がポインタを含むかどうかを示す情報を持っています。KindNoPointers
は、特定の型がポインタを含まないことを示すフラグです。runtime·new
関数では、割り当てるメモリがポインタを含まない場合、FlagNoPointers
というフラグをmallocgc
に渡します。これは、ガベージコレクタがポインタを含まないメモリ領域をスキャンする必要がないことを示し、ガベージコレクションの効率を向上させます。
技術的詳細
このコミットは、src/pkg/runtime/malloc.goc
ファイル内のruntime·new
関数に対する変更です。malloc.goc
は、Goランタイムのメモリ割り当てに関するC言語(Goのランタイムは一部C言語で記述されています)のソースファイルです。
変更前は、runtime·new
関数内で、m->racepc = runtime·getcallerpc(&typ);
という行が常に実行されていました。この行は、現在の呼び出し元のプログラムカウンタを取得し、それを現在のOSスレッド(m
)のracepc
フィールドに設定します。この操作は、Race Detectorが有効な場合にのみ意味を持ちます。
変更後は、この行がif(raceenabled)
という条件文で囲まれています。
if(raceenabled)
m->racepc = runtime·getcallerpc(&typ);
これにより、raceenabled
がtrue
(つまり、Race Detectorが有効)の場合にのみ、runtime·getcallerpc
の呼び出しとm->racepc
への代入が行われるようになります。raceenabled
がfalse
の場合、このブロックはスキップされ、不要な処理が実行されなくなります。
この変更は、特にRace Detectorを無効にしてビルドされたGoプログラムにおいて、わずかながらもパフォーマンス上の利益をもたらします。runtime·getcallerpc
はスタックを遡る操作を伴うため、それなりのコストがかかる可能性があります。このコストを不要な場合に回避することで、全体的なランタイムの効率が向上します。
コアとなるコードの変更箇所
変更はsrc/pkg/runtime/malloc.goc
ファイル内のruntime·new
関数にあります。
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -693,7 +693,8 @@ runtime·new(Type *typ, uint8 *ret)
{
uint32 flag;
- m->racepc = runtime·getcallerpc(&typ);
+ if(raceenabled)
+ m->racepc = runtime·getcallerpc(&typ);
flag = typ->kind&KindNoPointers ? FlagNoPointers : 0;
ret = runtime·mallocgc(typ->size, flag, 1, 1);
コアとなるコードの解説
runtime·new
関数は、Goのnew
組み込み関数が呼び出されたときに、ランタイムが新しいメモリを割り当てるために使用する内部関数です。
uint32 flag;
:メモリ割り当てに関するフラグを保持するための変数です。- 変更前の行:
m->racepc = runtime·getcallerpc(&typ);
この行は、Race Detectorが有効かどうかにかかわらず、常に実行されていました。runtime·getcallerpc(&typ)
は、runtime·new
を呼び出した関数のプログラムカウンタを取得し、それを現在のスレッド(m
)のracepc
フィールドに格納します。 - 変更後の行:
この変更により、if(raceenabled) m->racepc = runtime·getcallerpc(&typ);
m->racepc
への代入とruntime·getcallerpc
の呼び出しは、グローバル変数raceenabled
がtrue
の場合にのみ実行されるようになりました。raceenabled
は、GoプログラムがRace Detectorを有効にしてビルドされた場合にtrue
になります。これにより、Race Detectorが無効なビルドでは、この処理が完全にスキップされ、不要なオーバーヘッドが削減されます。 flag = typ->kind&KindNoPointers ? FlagNoPointers : 0;
:割り当てる型typ
がポインタを含まない型であるかどうかをチェックし、それに応じてFlagNoPointers
フラグを設定します。このフラグは、ガベージコレクタがメモリをスキャンする際のヒントとしてmallocgc
に渡されます。ret = runtime·mallocgc(typ->size, flag, 1, 1);
:実際にメモリを割り当てる関数です。typ->size
は割り当てるメモリのサイズ、flag
は上記で設定されたフラグ、残りの引数はガベージコレクションに関する内部的な情報です。
このコミットは、Goランタイムの細部にわたる最適化の一例であり、特定の機能(Race Detector)が有効な場合にのみ関連するコードパスを実行することで、全体的な効率を高めることを目的としています。
関連リンク
- Go言語のデータ競合検出器に関する公式ドキュメント:
- Go言語のランタイムソースコード(GitHub):
- このコミットが属するGoの変更リスト(CL):
参考にした情報源リンク
- The Go Race Detector - The Go Programming Language
- Go runtime source code on GitHub
- Go issue tracker and code review system (Gerrit)
- Go's memory allocator: Malloc and the TCMalloc algorithm (直接の参照ではないが、
mallocgc
の背景理解に役立つ) - Go's runtime scheduler (直接の参照ではないが、
m
構造体の背景理解に役立つ) - Go's garbage collector (直接の参照ではないが、
mallocgc
の背景理解に役立つ) - Go's type system and reflection (直接の参照ではないが、
Type
やKindNoPointers
の背景理解に役立つ) - Program counter - Wikipedia
- Call stack - Wikipedia
- Go runtime internals (various blog posts and talks) (一般的なGoランタイムの理解に役立つ)
- Go's runtime source code comments (Goのソースコード内のコメントは非常に詳細で参考になる)
- Go's runtime documentation (Goの標準ライブラリのドキュメント)
- Go's internal documentation (e.g.,
src/runtime/README
) (Goランタイムの内部構造に関する情報) - Go's
new
built-in function documentation