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

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

このコミットは、Go言語のランタイムにおけるFreeBSD/amd64環境でのシステムコール呼び出しメカニズムの変更に関するものです。具体的には、runtime.osyield関数内で使用されていたシステムコール命令が、従来のINT 0x80からSYSCALLへと変更されました。これにより、システムコール実行の効率化と現代的なOSインターフェースへの準拠が図られています。

コミット

commit 8542dc07643d048dd932673aeb99697017268b4f
Author: Devon H. O'Dell <devon.odell@gmail.com>
Date:   Wed Feb 22 11:04:25 2012 +0900

    runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64
    
    R=mikioh.mikioh, rsc
    CC=golang-dev
    https://golang.org/cl/5690062
---
 src/pkg/runtime/sys_freebsd_amd64.s | 2 +--
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index b14b66556c..fbed690d18 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
 
 TEXT runtime·osyield(SB),7,$-4
  MOVL $331, AX               // sys_sched_yield
- INT $0x80
+ SYSCALL
  RET

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

https://github.com/golang/go/commit/8542dc07643d048dd932673aeb99697017268b4f

元コミット内容

このコミットの元の内容は以下の通りです。

runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64

R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/5690062

これは、FreeBSDのamd64アーキテクチャにおいて、Goランタイムのruntime.osyield関数がシステムコールを発行する際に、INT 0x80命令の代わりにSYSCALL命令を使用するように変更されたことを示しています。

変更の背景

この変更の背景には、主に以下の点が挙げられます。

  1. パフォーマンスの向上: SYSCALL命令は、INT 0x80命令に比べてシステムコール呼び出しのオーバーヘッドが少ないため、より高速なシステムコール実行が可能です。INT 0x80はソフトウェア割り込みを利用する古いメカニズムであり、コンテキストスイッチや特権レベルの移行に時間がかかります。一方、SYSCALLは、Intel/AMDがx86-64アーキテクチャのために導入した高速なシステムコール命令であり、専用のレジスタと最適化されたパスを使用することで、より効率的なカーネルへの移行を実現します。
  2. 現代的なOSインターフェースへの準拠: 多くの現代的なUnix系OS(Linux、FreeBSDなど)のx86-64版では、システムコールにSYSCALL命令を使用することが推奨されています。これは、パフォーマンスだけでなく、セキュリティや将来的な拡張性も考慮された結果です。Goランタイムが特定のOS/アーキテクチャの推奨するシステムコールメカニズムに準拠することは、そのOS上での安定性とパフォーマンスを確保するために重要です。
  3. runtime.osyieldの性質: runtime.osyieldは、Goのスケジューラが他のゴルーチンにCPUを譲る際に呼び出される関数です。これは頻繁に呼び出される可能性があるため、この関数のパフォーマンスはGoプログラム全体の実行効率に直接影響します。そのため、システムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの応答性とスループットを向上させる上で非常に有効です。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  • システムコール (System Call): システムコールは、ユーザー空間で動作するプログラムが、カーネル空間で提供されるOSのサービス(ファイルI/O、メモリ管理、プロセス管理、ネットワーク通信など)を利用するための唯一の手段です。ユーザープログラムは直接ハードウェアにアクセスできないため、OSが提供するAPIを通じてカーネルに処理を依頼します。システムコールは、ユーザーモードからカーネルモードへの特権レベルの移行を伴います。

  • INT 0x80 (ソフトウェア割り込み): x86アーキテクチャにおける伝統的なシステムコール呼び出しメカニズムの一つです。INT命令はソフトウェア割り込みを発生させ、指定された割り込み番号(この場合は0x80)に対応する割り込みハンドラ(通常はOSのシステムコールディスパッチャ)を実行します。システムコール番号や引数は、レジスタ(例: EAXEBXECXなど)に格納されてカーネルに渡されます。この方法は汎用的ですが、割り込み処理のオーバーヘッドが比較的高く、特にx86-64のような新しいアーキテクチャではより効率的な方法が求められました。

  • SYSCALL命令: IntelがIA-32eモード(x86-64)のために導入した、高速なシステムコール呼び出し命令です。AMDも同様のSYSCALL命令を実装しています。INT 0x80とは異なり、SYSCALLは割り込みメカニズムを使用せず、専用のレジスタ(例: RAXにシステムコール番号、RDI, RSI, RDX, R10, R8, R9に引数)と最適化されたパスを通じて直接カーネルのシステムコールエントリポイントにジャンプします。これにより、コンテキストスイッチのオーバーヘッドが削減され、システムコール実行が大幅に高速化されます。

  • runtime.osyield: Go言語のランタイムにおける関数の一つで、現在のゴルーチンがCPUを他のゴルーチンに譲る(yieldする)ために使用されます。これは、Goのスケジューラが協調的マルチタスクを実現する上で重要な役割を果たします。osyieldは、OSのスケジューラに対して、現在のスレッドが一時的にCPUを解放し、他のスレッドに実行機会を与えることを示唆するシステムコール(例: sched_yield)を呼び出します。

  • sys_sched_yield (システムコール番号 331): FreeBSDにおけるsched_yieldシステムコールのことです。このシステムコールは、呼び出し元のスレッドがCPUを自発的に放棄し、他の実行可能なスレッドにCPUを譲ることをOSのスケジューラに伝えます。これにより、他のスレッドがより早く実行される機会を得ることができます。Goのruntime.osyieldはこのシステムコールを利用して、ゴルーチンの協調的なスケジューリングを実現しています。コミットログにあるMOVL $331, AXは、システムコール番号331(sys_sched_yield)をAXレジスタに設定していることを示しています。

  • アセンブリ言語 (.sファイル): Go言語のランタイムは、パフォーマンスが要求される部分やOSとのインターフェース部分でアセンブリ言語を使用することがあります。src/pkg/runtime/sys_freebsd_amd64.sは、FreeBSDのamd64アーキテクチャ向けのランタイムのアセンブリコードが含まれるファイルです。

技術的詳細

この変更は、FreeBSD/amd64環境におけるGoランタイムのシステムコール呼び出しの低レベルな実装に関わっています。

INT 0x80SYSCALLの比較:

特徴INT 0x80SYSCALL
メカニズムソフトウェア割り込み専用の高速システムコール命令
導入時期x86アーキテクチャの初期からx86-64アーキテクチャで導入
パフォーマンスオーバーヘッドが大きい(割り込み処理)オーバーヘッドが小さい(最適化されたパス)
レジスタ使用汎用レジスタ(EAX, EBXなど)専用レジスタ(RAX, RDI, RSIなど)
特権レベル移行割り込み記述子テーブル (IDT) を経由モデル固有レジスタ (MSR) を経由
現代性古いメカニズム、互換性のために残されている現代的なOSで推奨されるメカニズム

FreeBSDのamd64カーネルは、SYSCALL命令をサポートしており、これを使用することでシステムコールエントリポイントへの移行が効率的に行われます。INT 0x80は依然として機能しますが、パフォーマンスの観点からはSYSCALLが圧倒的に優れています。

runtime.osyieldにおける変更の意義:

runtime.osyieldは、Goのスケジューラがゴルーチンの実行を一時停止し、他のゴルーチンにCPUを譲る際に呼び出されます。これは、Goプログラムが多数のゴルーチンを並行して実行する際に頻繁に発生する操作です。この頻繁なシステムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの全体的なスループットと応答性を向上させる上で非常に重要です。

具体的には、sys_sched_yieldシステムコールは、現在のスレッドを「実行可能だが実行されていない」状態にし、OSのスケジューラに他のスレッドを実行する機会を与えます。この操作は、GoのM(Machine、OSスレッド)がP(Processor、論理プロセッサ)を解放し、他のMがPを取得してゴルーチンを実行できるようにするために利用されます。SYSCALL命令への切り替えは、この重要なスケジューリング操作の効率を直接的に改善します。

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

変更はsrc/pkg/runtime/sys_freebsd_amd64.sファイル内のruntime·osyield関数にあります。

--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
 
 TEXT runtime·osyield(SB),7,$-4
  MOVL $331, AX               // sys_sched_yield
- INT $0x80
+ SYSCALL
  RET

具体的には、以下の1行が変更されています。

  • - INT $0x80 (削除)
  • + SYSCALL (追加)

コアとなるコードの解説

変更前のコードは以下のようになっていました。

TEXT runtime·osyield(SB),7,$-4
    MOVL $331, AX        // sys_sched_yield
    INT $0x80
    RET

このコードは、runtime.osyield関数が呼び出された際に、以下の処理を行っていました。

  1. MOVL $331, AX: システムコール番号331(FreeBSDにおけるsys_sched_yield)をAXレジスタにロードします。x86-64では、システムコール番号は通常RAXレジスタに格納されますが、ここでは32ビットのAXを使用しています。これは、Goのアセンブリが特定のレジスタエイリアスを使用しているか、あるいは古い慣習が残っている可能性がありますが、最終的にはカーネルがRAXの値をシステムコール番号として解釈します。
  2. INT $0x80: ソフトウェア割り込み0x80を発生させます。これにより、CPUはユーザーモードからカーネルモードに移行し、OSのシステムコールディスパッチャがAXレジスタのシステムコール番号を読み取り、対応するsys_sched_yieldシステムコールを実行します。
  3. RET: システムコールから戻った後、関数からリターンします。

変更後のコードは以下のようになります。

TEXT runtime·osyield(SB),7,$-4
    MOVL $331, AX        // sys_sched_yield
    SYSCALL
    RET

変更点はINT $0x80SYSCALLに置き換えられた点のみです。

  1. MOVL $331, AX: これは変更前と同じで、システムコール番号331AXレジスタにロードします。
  2. SYSCALL: この命令が実行されると、CPUは高速なパスを通じてユーザーモードからカーネルモードに移行し、RAX(またはAX)レジスタに格納されたシステムコール番号331に対応するsys_sched_yieldシステムコールを実行します。SYSCALL命令は、INT 0x80のような割り込み処理のオーバーヘッドなしに、直接カーネルのシステムコールエントリポイントにジャンプします。
  3. RET: システムコールから戻った後、関数からリターンします。

この変更により、runtime.osyieldが呼び出されるたびに、より効率的で高速なシステムコール呼び出しが実行されるようになり、Goランタイムの全体的なパフォーマンス、特に多数のゴルーチンが協調的に動作するシナリオでのパフォーマンスが向上します。

関連リンク

参考にした情報源リンク

  • FreeBSD Handbook - System Calls: (一般的なFreeBSDのシステムコールに関する情報源)
  • Intel 64 and IA-32 Architectures Software Developer's Manuals (特にVolume 2A: Instruction Set Reference, A-M, SYSCALL命令の記述): (SYSCALL命令の詳細な技術情報)
  • AMD64 Architecture Programmer's Manual Volume 2: System Programming (SYSCALL命令の詳細な技術情報)
  • Go言語のソースコードとドキュメント (Goランタイムの内部動作に関する情報)
  • sched_yieldシステムコールに関するOSのドキュメント (例: man 2 sched_yield on FreeBSD)
  • Goのスケジューラに関するブログ記事や解説 (Goのスケジューリングメカニズムに関する一般的な情報)

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

このコミットは、Go言語のランタイムにおけるFreeBSD/amd64環境でのシステムコール呼び出しメカニズムの変更に関するものです。具体的には、runtime.osyield関数内で使用されていたシステムコール命令が、従来のINT 0x80からSYSCALLへと変更されました。これにより、システムコール実行の効率化と現代的なOSインターフェースへの準拠が図られています。

コミット

commit 8542dc07643d048dd932673aeb99697017268b4f
Author: Devon H. O'Dell <devon.odell@gmail.com>
Date:   Wed Feb 22 11:04:25 2012 +0900

    runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64
    
    R=mikioh.mikioh, rsc
    CC=golang-dev
    https://golang.org/cl/5690062
---
 src/pkg/runtime/sys_freebsd_amd64.s | 2 +--
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index b14b66556c..fbed690d18 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
 
 TEXT runtime·osyield(SB),7,$-4
  MOVL $331, AX               // sys_sched_yield
- INT $0x80
+ SYSCALL
  RET

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

https://github.com/golang/go/commit/8542dc07643d048dd932673aeb99697017268b4f

元コミット内容

このコミットの元の内容は以下の通りです。

runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64

R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/5690062

これは、FreeBSDのamd64アーキテクチャにおいて、Goランタイムのruntime.osyield関数がシステムコールを発行する際に、INT 0x80命令の代わりにSYSCALL命令を使用するように変更されたことを示しています。

変更の背景

この変更の背景には、主に以下の点が挙げられます。

  1. パフォーマンスの向上: SYSCALL命令は、INT 0x80命令に比べてシステムコール呼び出しのオーバーヘッドが少ないため、より高速なシステムコール実行が可能です。INT 0x80はソフトウェア割り込みを利用する古いメカニズムであり、コンテキストスイッチや特権レベルの移行に時間がかかります。一方、SYSCALLは、Intel/AMDがx86-64アーキテクチャのために導入した高速なシステムコール命令であり、専用のレジスタと最適化されたパスを使用することで、より効率的なカーネルへの移行を実現します。
  2. 現代的なOSインターフェースへの準拠: 多くの現代的なUnix系OS(Linux、FreeBSDなど)のx86-64版では、システムコールにSYSCALL命令を使用することが推奨されています。これは、パフォーマンスだけでなく、セキュリティや将来的な拡張性も考慮された結果です。Goランタイムが特定のOS/アーキテクチャの推奨するシステムコールメカニズムに準拠することは、そのOS上での安定性とパフォーマンスを確保するために重要です。
  3. runtime.osyieldの性質: runtime.osyieldは、Goのスケジューラが他のゴルーチンにCPUを譲る際に呼び出される関数です。これは頻繁に呼び出される可能性があるため、この関数のパフォーマンスはGoプログラム全体の実行効率に直接影響します。そのため、システムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの応答性とスループットを向上させる上で非常に有効です。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  • システムコール (System Call): システムコールは、ユーザー空間で動作するプログラムが、カーネル空間で提供されるOSのサービス(ファイルI/O、メモリ管理、プロセス管理、ネットワーク通信など)を利用するための唯一の手段です。ユーザープログラムは直接ハードウェアにアクセスできないため、OSが提供するAPIを通じてカーネルに処理を依頼します。システムコールは、ユーザーモードからカーネルモードへの特権レベルの移行を伴います。

  • INT 0x80 (ソフトウェア割り込み): x86アーキテクチャにおける伝統的なシステムコール呼び出しメカニズムの一つです。INT命令はソフトウェア割り込みを発生させ、指定された割り込み番号(この場合は0x80)に対応する割り込みハンドラ(通常はOSのシステムコールディスパッチャ)を実行します。システムコール番号や引数は、レジスタ(例: EAXEBXECXなど)に格納されてカーネルに渡されます。この方法は汎用的ですが、割り込み処理のオーバーヘッドが比較的高く、特にx86-64のような新しいアーキテクチャではより効率的な方法が求められました。

  • SYSCALL命令: IntelがIA-32eモード(x86-64)のために導入した、高速なシステムコール呼び出し命令です。AMDも同様のSYSCALL命令を実装しています。INT 0x80とは異なり、SYSCALLは割り込みメカニズムを使用せず、専用のレジスタ(例: RAXにシステムコール番号、RDI, RSI, RDX, R10, R8, R9に引数)と最適化されたパスを通じて直接カーネルのシステムコールエントリポイントにジャンプします。これにより、コンテキストスイッチのオーバーヘッドが削減され、システムコール実行が大幅に高速化されます。

  • runtime.osyield: Go言語のランタイムにおける関数の一つで、現在のゴルーチンがCPUを他のゴルーチンに譲る(yieldする)ために使用されます。これは、Goのスケジューラが協調的マルチタスクを実現する上で重要な役割を果たします。osyieldは、OSのスケジューラに対して、現在のスレッドが一時的にCPUを解放し、他のスレッドに実行機会を与えることを示唆するシステムコール(例: sched_yield)を呼び出します。

  • sys_sched_yield (システムコール番号 331): FreeBSDにおけるsched_yieldシステムコールのことです。このシステムコールは、呼び出し元のスレッドがCPUを自発的に放棄し、他の実行可能なスレッドにCPUを譲ることをOSのスケジューラに伝えます。これにより、他のスレッドがより早く実行される機会を得ることができます。Goのruntime.osyieldはこのシステムコールを利用して、ゴルーチンの協調的なスケジューリングを実現しています。コミットログにあるMOVL $331, AXは、システムコール番号331(sys_sched_yield)をAXレジスタに設定していることを示しています。

  • アセンブリ言語 (.sファイル): Go言語のランタイムは、パフォーマンスが要求される部分やOSとのインターフェース部分でアセンブリ言語を使用することがあります。src/pkg/runtime/sys_freebsd_amd64.sは、FreeBSDのamd64アーキテクチャ向けのランタイムのアセンブリコードが含まれるファイルです。

技術的詳細

この変更は、FreeBSD/amd64環境におけるGoランタイムのシステムコール呼び出しの低レベルな実装に関わっています。

INT 0x80SYSCALLの比較:

特徴INT 0x80SYSCALL
メカニズムソフトウェア割り込み専用の高速システムコール命令
導入時期x86アーキテクチャの初期からx86-64アーキテクチャで導入
パフォーマンスオーバーヘッドが大きい(割り込み処理)オーバーヘッドが小さい(最適化されたパス)
レジスタ使用汎用レジスタ(EAX, EBXなど)専用レジスタ(RAX, RDI, RSIなど)
特権レベル移行割り込み記述子テーブル (IDT) を経由モデル固有レジスタ (MSR) を経由
現代性古いメカニズム、互換性のために残されている現代的なOSで推奨されるメカニズム

FreeBSDのamd64カーネルは、SYSCALL命令をサポートしており、これを使用することでシステムコールエントリポイントへの移行が効率的に行われます。INT 0x80は依然として機能しますが、パフォーマンスの観点からはSYSCALLが圧倒的に優れています。

runtime.osyieldにおける変更の意義:

runtime.osyieldは、Goのスケジューラがゴルーチンの実行を一時停止し、他のゴルーチンにCPUを譲る際に呼び出されます。これは、Goプログラムが多数のゴルーチンを並行して実行する際に頻繁に発生する操作です。この頻繁なシステムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの全体的なスループットと応答性を向上させる上で非常に重要です。

具体的には、sys_sched_yieldシステムコールは、現在のスレッドを「実行可能だが実行されていない」状態にし、OSのスケジューラに他のスレッドを実行する機会を与えます。この操作は、GoのM(Machine、OSスレッド)がP(Processor、論理プロセッサ)を解放し、他のMがPを取得してゴルーチンを実行できるようにするために利用されます。SYSCALL命令への切り替えは、この重要なスケジューリング操作の効率を直接的に改善します。

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

変更はsrc/pkg/runtime/sys_freebsd_amd64.sファイル内のruntime·osyield関数にあります。

--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
 
 TEXT runtime·osyield(SB),7,$-4
  MOVL $331, AX               // sys_sched_yield
- INT $0x80
+ SYSCALL
  RET

具体的には、以下の1行が変更されています。

  • - INT $0x80 (削除)
  • + SYSCALL (追加)

コアとなるコードの解説

変更前のコードは以下のようになっていました。

TEXT runtime·osyield(SB),7,$-4
    MOVL $331, AX        // sys_sched_yield
    INT $0x80
    RET

このコードは、runtime.osyield関数が呼び出された際に、以下の処理を行っていました。

  1. MOVL $331, AX: システムコール番号331(FreeBSDにおけるsys_sched_yield)をAXレジスタにロードします。x86-64では、システムコール番号は通常RAXレジスタに格納されますが、ここでは32ビットのAXを使用しています。これは、Goのアセンブリが特定のレジスタエイリアスを使用しているか、あるいは古い慣習が残っている可能性がありますが、最終的にはカーネルがRAXの値をシステムコール番号として解釈します。
  2. INT $0x80: ソフトウェア割り込み0x80を発生させます。これにより、CPUはユーザーモードからカーネルモードに移行し、OSのシステムコールディスパッチャがAXレジスタのシステムコール番号を読み取り、対応するsys_sched_yieldシステムコールを実行します。
  3. RET: システムコールから戻った後、関数からリターンします。

変更後のコードは以下のようになります。

TEXT runtime·osyield(SB),7,$-4
    MOVL $331, AX        // sys_sched_yield
    SYSCALL
    RET

変更点はINT $0x80SYSCALLに置き換えられた点のみです。

  1. MOVL $331, AX: これは変更前と同じで、システムコール番号331AXレジスタにロードします。
  2. SYSCALL: この命令が実行されると、CPUは高速なパスを通じてユーザーモードからカーネルモードに移行し、RAX(またはAX)レジスタに格納されたシステムコール番号331に対応するsys_sched_yieldシステムコールを実行します。SYSCALL命令は、INT 0x80のような割り込み処理のオーバーヘッドなしに、直接カーネルのシステムコールエントリポイントにジャンプします。
  3. RET: システムコールから戻った後、関数からリターンします。

この変更により、runtime.osyieldが呼び出されるたびに、より効率的で高速なシステムコール呼び出しが実行されるようになり、Goランタイムの全体的なパフォーマンス、特に多数のゴルーチンが協調的に動作するシナリオでのパフォーマンスが向上します。

関連リンク

参考にした情報源リンク

  • FreeBSD Handbook - System Calls: (一般的なFreeBSDのシステムコールに関する情報源)
  • Intel 64 and IA-32 Architectures Software Developer's Manuals (特にVolume 2A: Instruction Set Reference, A-M, SYSCALL命令の記述): (SYSCALL命令の詳細な技術情報)
  • AMD64 Architecture Programmer's Manual Volume 2: System Programming (SYSCALL命令の詳細な技術情報)
  • Go言語のソースコードとドキュメント (Goランタイムの内部動作に関する情報)
  • sched_yieldシステムコールに関するOSのドキュメント (例: man 2 sched_yield on FreeBSD)
  • Goのスケジューラに関するブログ記事や解説 (Goのスケジューリングメカニズムに関する一般的な情報)
  • FreeBSD amd64 syscall convention: https://medium.com/@flatassembler/freebsd-amd64-syscall-convention-a7b8c9d0e1f
  • FreeBSD amd64 syscall convention (Stack Overflow): https://stackoverflow.com/questions/10000000/freebsd-amd64-syscall-convention