[インデックス 11654] ファイルの概要
このコミットは、Go言語のツールチェイン(特にアセンブラ 8a
とリンカ 8l
)に RDTSC
(Read Time-Stamp Counter) 命令のサポートを追加し、Goランタイムがこの命令を利用するように変更したものです。これにより、Goプログラム内でCPUのタイムスタンプカウンタを直接読み取ることが可能になり、より高精度な時間計測やプロファイリングの基盤が提供されます。
コミット
commit 6392b43a1583f5ccf5a3f7c38f096e8dd5403b0d
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Mon Feb 6 12:49:28 2012 -0500
8a, 8l: implement support for RDTSC instruction.
Also modify runtime/asm_386.s to use it.
R=rsc
CC=golang-dev
https://golang.org/cl/5634043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6392b43a1583f5ccf5a3f7c38f096e8dd5403b0d
元コミット内容
8a, 8l: implement support for RDTSC instruction.
Also modify runtime/asm_386.s to use it.
R=rsc
CC=golang-dev
https://golang.org/cl/5634043
変更の背景
この変更の背景には、Go言語のランタイムがより低レベルで高精度な時間計測機能を利用できるようにするという目的があります。RDTSC
命令は、CPUのタイムスタンプカウンタを直接読み取るための命令であり、非常に細かい粒度での時間計測を可能にします。
Go言語のランタイムは、スケジューラやガベージコレクタなど、内部的な処理で時間計測を必要とします。また、ユーザーがプログラムのパフォーマンスをプロファイリングする際にも、高精度な時間情報が求められることがあります。既存の時間計測メカニズムでは不十分な場合や、特定のハードウェア特性を利用してより効率的な時間計測を行いたい場合に、RDTSC
命令のサポートが重要になります。
このコミット以前は、Goのアセンブラ 8a
は RDTSC
命令を直接サポートしていませんでした。そのため、runtime/asm_386.s
のようなアセンブリファイルで RDTSC
を使用するには、BYTE $0x0F; BYTE $0x31;
のようにバイトコードを直接記述する必要がありました。これは可読性が低く、保守性も劣ります。このコミットは、ツールチェインレベルで RDTSC
を正式にサポートすることで、この問題を解決し、よりクリーンなアセンブリコードの記述を可能にしています。
前提知識の解説
RDTSC (Read Time-Stamp Counter) 命令
RDTSC
は、IntelおよびAMDのx86アーキテクチャのプロセッサが提供するCPU命令です。この命令は、プロセッサが起動してからのクロックサイクル数をカウントする64ビットのレジスタである「タイムスタンプカウンタ (TSC)」の値を読み取ります。
- 機能:
RDTSC
命令を実行すると、TSCの現在の値がEDX:EAX
レジスタペア(上位32ビットがEDX
、下位32ビットがEAX
)に格納されます。 - 用途:
- 高精度な時間計測: ナノ秒レベルの非常に細かい時間計測が可能です。マイクロベンチマークやプロファイリングにおいて、特定のコードブロックの実行時間を正確に測定するために使用されます。
- 乱数生成のシード: TSCの値は予測が難しいため、乱数生成器のシードとして利用されることがあります。
- イベントのタイムスタンプ: システム内のイベント発生時刻を記録するために使用されます。
- 注意点:
- 周波数変動: 現代のCPUでは、省電力機能やターボブーストなどによりCPUの動作周波数が動的に変動することがあります。この場合、TSCのカウントは一定の時間を表さない可能性があります。そのため、正確な壁時計時間(リアルタイム)を測定する目的には適さない場合があります。
- マルチコア/マルチプロセッサ: 複数のコアやプロセッサを持つシステムでは、各コア/プロセッサが独立したTSCを持つ場合があり、それらの同期が保証されないことがあります。これにより、異なるコアで実行されるスレッド間でTSCの値が比較できない問題が発生する可能性があります。
- 仮想化環境: 仮想マシン環境では、ハイパーバイザがTSCの動作をエミュレートまたは仮想化するため、物理ハードウェアとは異なる挙動を示すことがあります。
Go言語のツールチェイン
Go言語は、独自のコンパイラ、アセンブラ、リンカを含む完全なツールチェインを持っています。
8a
(アセンブラ): x86アーキテクチャ(32ビット)向けのアセンブラです。アセンブリ言語で書かれたソースコード(.s
ファイル)をオブジェクトファイルに変換します。8l
(リンカ): x86アーキテクチャ(32ビット)向けのリンカです。オブジェクトファイルを結合し、実行可能ファイルを生成します。runtime
パッケージ: Go言語のランタイムシステムを実装しているパッケージです。ガベージコレクタ、スケジューラ、メモリ管理、システムコールインターフェースなど、Goプログラムの実行に必要な低レベルな機能を提供します。runtime
パッケージ内には、特定のアーキテクチャ向けのアセンブリコード(例:asm_386.s
)が含まれることがあります。
技術的詳細
このコミットは、Go言語のツールチェインとランタイムにおいて、RDTSC
命令をネイティブにサポートするための変更を導入しています。
-
アセンブラ
8a
でのRDTSC
命令の認識:src/cmd/8a/lex.c
は、アセンブラの字句解析器(lexer)のソースコードです。このファイルにRDTSC
という新しいキーワードが追加され、アセンブラがこの命令を認識できるようになります。LTYPE0
は、オペランドを持たない命令(ゼロオペランド命令)であることを示します。ARDTSC
は、RDTSC
命令に対応する内部的なオペレーションコード(opcode)の定数です。
-
リンカ
8l
でのARDTSC
オペコードの定義:src/cmd/8l/8.out.h
は、リンカが使用するオペレーションコードの定義を含むヘッダファイルです。ここにARDTSC
が新しいエントリとして追加されます。これにより、リンカがARDTSC
オペコードを理解し、適切に処理できるようになります。
-
リンカ
8l
でのRDTSC
命令の機械語コードへの変換規則の追加:src/cmd/8l/optab.c
は、リンカがアセンブリ命令を対応する機械語コード(バイト列)に変換するためのテーブル(Optab
)を定義しています。ARDTSC
命令に対して、機械語コード0x0f, 0x31
が割り当てられます。これはRDTSC
命令の実際のオペコードです。ynone
は、この命令がオペランドを持たないことを示します。Pm
は、命令が特定のプレフィックス(ここでは0x0F
)を持つことを示します。
-
ランタイムのアセンブリコード
asm_386.s
の変更:src/pkg/runtime/asm_386.s
は、Goランタイムの32ビットx86アーキテクチャ向けアセンブリコードです。- 以前は
runtime·cputicks
関数内でRDTSC
命令を使用するためにBYTE $0x0F; BYTE $0x31;
のように直接バイトコードを記述していました。これは、アセンブラがRDTSC
を直接認識しなかったためです。 - このコミットにより、ツールチェインが
RDTSC
をサポートするようになったため、より可読性の高いRDTSC
というニーモニックを直接使用できるようになりました。
これらの変更により、Goのツールチェインは RDTSC
命令をネイティブにサポートし、開発者はアセンブリコード内でこの命令を直接、かつクリーンに記述できるようになります。これにより、GoランタイムがCPUのタイムスタンプカウンタをより効率的かつ安全に利用できるようになり、高精度な時間計測機能の基盤が強化されます。
コアとなるコードの変更箇所
src/cmd/8a/lex.c
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -445,6 +445,7 @@ struct
"RCRB", LTYPE3, ARCRB,
"RCRL", LTYPE3, ARCRL,
"RCRW", LTYPE3, ARCRW,
+ "RDTSC", LTYPE0, ARDTSC,
"REP", LTYPE0, AREP,
"REPN", LTYPE0, AREPN,
"RET", LTYPE0, ARET,
src/cmd/8l/8.out.h
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -395,7 +395,9 @@ enum as
ACMPXCHGL,
ACMPXCHGW,
ACMPXCHG8B,
-\t
+
+ ARDTSC,
+
AXADDB,
AXADDL,
AXADDW,
src/cmd/8l/optab.c
--- a/src/cmd/8l/optab.c
+++ b/src/cmd/8l/optab.c
@@ -707,6 +707,8 @@ Optab optab[] =
{ ACMPXCHGW, yrl_ml, Pm, 0xb1 },
{ ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+\t{ ARDTSC, ynone, Pm, 0x31 },
+
{ AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
{ AXADDL, yrl_ml, Pm, 0xc1 },
{ AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
src/pkg/runtime/asm_386.s
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -527,7 +527,7 @@ TEXT runtime·getcallersp(SB), 7, $0
// int64 runtime·cputicks(void), so really
// void runtime·cputicks(int64 *ticks)
TEXT runtime·cputicks(SB),7,$0
-\tBYTE\t$0x0F; BYTE $0x31; // RDTSC; not supported by 8a
+\tRDTSC
MOVL ret+0(FP), DI
MOVL AX, 0(DI)
MOVL DX, 4(DI)
コアとなるコードの解説
src/cmd/8a/lex.c
の変更
{"RDTSC", LTYPE0, ARDTSC,}
というエントリがkeywords
構造体配列に追加されました。- これは、アセンブラ
8a
がRDTSC
という文字列を認識し、それをオペランドを持たない命令 (LTYPE0
) として扱い、内部的にはARDTSC
というオペコードにマッピングすることを示します。これにより、アセンブリソースコードでRDTSC
と記述できるようになります。
src/cmd/8l/8.out.h
の変更
enum as
列挙型にARDTSC,
が追加されました。- この列挙型は、リンカ
8l
が認識するすべてのアセンブリ命令の内部表現を定義しています。ARDTSC
の追加により、リンカがRDTSC
命令を処理するための準備が整いました。
src/cmd/8l/optab.c
の変更
Optab optab[]
配列に{ ARDTSC, ynone, Pm, 0x31 },
という新しいエントリが追加されました。- これは、リンカが
ARDTSC
オペコードを実際の機械語コードに変換するための規則を定義しています。ARDTSC
: 内部オペコード。ynone
: オペランドがないことを示す。Pm
: 命令が0x0F
というプレフィックスを持つことを示す。0x31
:0x0F
プレフィックスに続く命令のオペコード。
- したがって、
RDTSC
命令は0x0F 0x31
という2バイトの機械語コードに変換されます。
src/pkg/runtime/asm_386.s
の変更
runtime·cputicks
関数内で、以前はBYTE $0x0F; BYTE $0x31;
と直接バイトコードを記述してRDTSC
命令を生成していました。これは、アセンブラがRDTSC
ニーモニックを直接サポートしていなかったためです。- このコミットにより、ツールチェインが
RDTSC
を認識するようになったため、より簡潔で可読性の高いRDTSC
というニーモニックに置き換えられました。 - この関数は、CPUのタイムスタンプカウンタを読み取り、その値を
ret+0(FP)
(フレームポインタからのオフセットで指定される戻り値のアドレス) に格納します。AX
レジスタにはTSCの下位32ビット、DX
レジスタには上位32ビットが格納されるため、これらを結合して64ビットの値を返す処理が行われています。
これらの変更により、Goのツールチェインは RDTSC
命令を完全にサポートし、ランタイムがこの命令をより自然な形で利用できるようになりました。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- このコミットのChangeList (Gerrit): https://golang.org/cl/5634043
参考にした情報源リンク
- Intel 64 and IA-32 Architectures Software Developer's Manuals (RDTSC 命令の詳細): https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
- AMD64 Architecture Programmer's Manuals (RDTSC 命令の詳細): https://developer.amd.com/resources/developer-guides-manuals/
- Go Assembly Language (Goのアセンブリ言語に関するドキュメント): https://go.dev/doc/asm
- Goのツールチェインに関する一般的な情報 (Goのコンパイラ、アセンブラ、リンカの役割): https://go.dev/doc/ (Goの公式ドキュメント全般)