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

[インデックス 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 -racego build -racego test -raceなどのコマンドで有効にできます。

mallocgc

runtime·mallocgcは、Goランタイムにおける主要なメモリ割り当て関数の一つです。これは、ガベージコレクタによって管理されるヒープメモリから新しいメモリブロックを割り当てます。mallocgcは、割り当てられたメモリをゼロ初期化し、ガベージコレクタがそのメモリを追跡できるように必要なメタデータを設定します。

runtime·getcallerpc

runtime·getcallerpcは、現在の関数の呼び出し元のプログラムカウンタ(PC)を取得するランタイム関数です。PCは、実行中の命令のアドレスを示すレジスタであり、デバッグやプロファイリング、そしてRace Detectorのようなツールがコードの実行パスを追跡するために使用されます。この関数は、通常、スタックフレームを遡って呼び出し元のPCを特定します。

raceenabled

raceenabledは、Goランタイム内部で使用されるグローバルなブール型変数です。この変数は、プログラムがRace Detectorを有効にしてビルドされたかどうかを示します。raceenabledtrueの場合、Race Detector関連の追加の監視および記録ロジックが実行されます。falseの場合、これらのロジックはスキップされ、パフォーマンスのオーバーヘッドが削減されます。

m->racepc

mは、Goランタイムにおけるm構造体(runtime.m)を指すことが多いです。これは、OSのスレッドを表す構造体であり、ゴルーチンの実行、スタック管理、スケジューリングなど、スレッド固有の情報を保持します。m->racepcは、このm構造体内のフィールドで、Race Detectorが有効な場合に、メモリ割り当てが行われた時点のプログラムカウンタを記録するために使用されます。これにより、競合が発生した際に、どのスレッド(およびそのスレッドが実行していたゴルーチン)が問題のメモリにアクセスしたかを特定する手助けとなります。

KindNoPointersFlagNoPointers

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);

これにより、raceenabledtrue(つまり、Race Detectorが有効)の場合にのみ、runtime·getcallerpcの呼び出しとm->racepcへの代入が行われるようになります。raceenabledfalseの場合、このブロックはスキップされ、不要な処理が実行されなくなります。

この変更は、特に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組み込み関数が呼び出されたときに、ランタイムが新しいメモリを割り当てるために使用する内部関数です。

  1. uint32 flag;:メモリ割り当てに関するフラグを保持するための変数です。
  2. 変更前の行: m->racepc = runtime·getcallerpc(&typ); この行は、Race Detectorが有効かどうかにかかわらず、常に実行されていました。runtime·getcallerpc(&typ)は、runtime·newを呼び出した関数のプログラムカウンタを取得し、それを現在のスレッド(m)のracepcフィールドに格納します。
  3. 変更後の行:
    if(raceenabled)
    	m->racepc = runtime·getcallerpc(&typ);
    
    この変更により、m->racepcへの代入とruntime·getcallerpcの呼び出しは、グローバル変数raceenabledtrueの場合にのみ実行されるようになりました。raceenabledは、GoプログラムがRace Detectorを有効にしてビルドされた場合にtrueになります。これにより、Race Detectorが無効なビルドでは、この処理が完全にスキップされ、不要なオーバーヘッドが削減されます。
  4. flag = typ->kind&KindNoPointers ? FlagNoPointers : 0;:割り当てる型typがポインタを含まない型であるかどうかをチェックし、それに応じてFlagNoPointersフラグを設定します。このフラグは、ガベージコレクタがメモリをスキャンする際のヒントとしてmallocgcに渡されます。
  5. ret = runtime·mallocgc(typ->size, flag, 1, 1);:実際にメモリを割り当てる関数です。typ->sizeは割り当てるメモリのサイズ、flagは上記で設定されたフラグ、残りの引数はガベージコレクションに関する内部的な情報です。

このコミットは、Goランタイムの細部にわたる最適化の一例であり、特定の機能(Race Detector)が有効な場合にのみ関連するコードパスを実行することで、全体的な効率を高めることを目的としています。

関連リンク

参考にした情報源リンク

このコミットは、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 -racego build -racego test -raceなどのコマンドで有効にできます。

mallocgc

runtime·mallocgcは、Goランタイムにおける主要なメモリ割り当て関数の一つです。これは、ガベージコレクタによって管理されるヒープメモリから新しいメモリブロックを割り当てます。mallocgcは、割り当てられたメモリをゼロ初期化し、ガベージコレクタがそのメモリを追跡できるように必要なメタデータを設定します。

runtime·getcallerpc

runtime·getcallerpcは、現在の関数の呼び出し元のプログラムカウンタ(PC)を取得するランタイム関数です。PCは、実行中の命令のアドレスを示すレジスタであり、デバッグやプロファイリング、そしてRace Detectorのようなツールがコードの実行パスを追跡するために使用されます。この関数は、通常、スタックフレームを遡って呼び出し元のPCを特定します。

raceenabled

raceenabledは、Goランタイム内部で使用されるグローバルなブール型変数です。この変数は、プログラムがRace Detectorを有効にしてビルドされたかどうかを示します。raceenabledtrueの場合、Race Detector関連の追加の監視および記録ロジックが実行されます。falseの場合、これらのロジックはスキップされ、パフォーマンスのオーバーヘッドが削減されます。

m->racepc

mは、Goランタイムにおけるm構造体(runtime.m)を指すことが多いです。これは、OSのスレッドを表す構造体であり、ゴルーチンの実行、スタック管理、スケジューリングなど、スレッド固有の情報を保持します。m->racepcは、このm構造体内のフィールドで、Race Detectorが有効な場合に、メモリ割り当てが行われた時点のプログラムカウンタを記録するために使用されます。これにより、競合が発生した際に、どのスレッド(およびそのスレッドが実行していたゴルーチン)が問題のメモリにアクセスしたかを特定する手助けとなります。

KindNoPointersFlagNoPointers

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);

これにより、raceenabledtrue(つまり、Race Detectorが有効)の場合にのみ、runtime·getcallerpcの呼び出しとm->racepcへの代入が行われるようになります。raceenabledfalseの場合、このブロックはスキップされ、不要な処理が実行されなくなります。

この変更は、特に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組み込み関数が呼び出されたときに、ランタイムが新しいメモリを割り当てるために使用する内部関数です。

  1. uint32 flag;:メモリ割り当てに関するフラグを保持するための変数です。
  2. 変更前の行: m->racepc = runtime·getcallerpc(&typ); この行は、Race Detectorが有効かどうかにかかわらず、常に実行されていました。runtime·getcallerpc(&typ)は、runtime·newを呼び出した関数のプログラムカウンタを取得し、それを現在のスレッド(m)のracepcフィールドに格納します。
  3. 変更後の行:
    if(raceenabled)
    	m->racepc = runtime·getcallerpc(&typ);
    
    この変更により、m->racepcへの代入とruntime·getcallerpcの呼び出しは、グローバル変数raceenabledtrueの場合にのみ実行されるようになりました。raceenabledは、GoプログラムがRace Detectorを有効にしてビルドされた場合にtrueになります。これにより、Race Detectorが無効なビルドでは、この処理が完全にスキップされ、不要なオーバーヘッドが削減されます。
  4. flag = typ->kind&KindNoPointers ? FlagNoPointers : 0;:割り当てる型typがポインタを含まない型であるかどうかをチェックし、それに応じてFlagNoPointersフラグを設定します。このフラグは、ガベージコレクタがメモリをスキャンする際のヒントとしてmallocgcに渡されます。
  5. ret = runtime·mallocgc(typ->size, flag, 1, 1);:実際にメモリを割り当てる関数です。typ->sizeは割り当てるメモリのサイズ、flagは上記で設定されたフラグ、残りの引数はガベージコレクションに関する内部的な情報です。

このコミットは、Goランタイムの細部にわたる最適化の一例であり、特定の機能(Race Detector)が有効な場合にのみ関連するコードパスを実行することで、全体的な効率を高めることを目的としています。

関連リンク

参考にした情報源リンク