[インデックス 17268] ファイルの概要
このコミットは、Go言語のネットワークパッケージにおいて、FreeBSDおよびOpenBSDシステムでのランタイム統合型ネットワークポーラー(network pollster)を有効にするための変更です。これにより、これらのOS上でのネットワークI/Oのパフォーマンスが大幅に改善されています。
コミット
commit cb3b292201861b8052c665ccad6cf12ff0c8d839
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Thu Aug 15 21:10:03 2013 +0900
net: enable runtime-integrated network pollster on freebsd, openbsd
Fixes #5199.
Benchmark results on freebsd/amd64 (virtual machine):
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot-2 184566 187164 +1.41%
BenchmarkTCP4OneShotTimeout-2 215558 187722 -12.91%
BenchmarkTCP4Persistent-2 59686 41294 -30.81%
BenchmarkTCP4PersistentTimeout-2 60692 39974 -34.14%
BenchmarkTCP6OneShot-2 226595 223688 -1.28%
BenchmarkTCP6OneShotTimeout-2 253144 225161 -11.05%
BenchmarkTCP6Persistent-2 69157 55605 -19.60%
BenchmarkTCP6PersistentTimeout-2 70426 53805 -23.60%
BenchmarkTCP4ConcurrentReadWrite-2 53878 56087 +4.10%
BenchmarkTCP6ConcurrentReadWrite-2 66538 68190 +2.48%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot-2 39 36 -7.69%
BenchmarkTCP4OneShotTimeout-2 42 36 -14.29%
BenchmarkTCP4Persistent-2 1 0 -100.00%
BenchmarkTCP4PersistentTimeout-2 1 0 -100.00%
BenchmarkTCP6OneShot-2 41 36 -12.20%
BenchmarkTCP6OneShotTimeout-2 43 36 -16.28%
BenchmarkTCP6Persistent-2 1 0 -100.00%
BenchmarkTCP6PersistentTimeout-2 1 0 -100.00%
BenchmarkTCP4ConcurrentReadWrite-2 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite-2 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot-2 3084 2544 -17.51%\n BenchmarkTCP4OneShotTimeout-2 3129 2519 -19.50%\n BenchmarkTCP4Persistent-2 30 0 -100.00%\n BenchmarkTCP4PersistentTimeout-2 31 0 -100.00%\n BenchmarkTCP6OneShot-2 3297 2660 -19.32%\n BenchmarkTCP6OneShotTimeout-2 3306 2655 -19.69%\n BenchmarkTCP6Persistent-2 31 0 -100.00%\n BenchmarkTCP6PersistentTimeout-2 29 0 -100.00%\n BenchmarkTCP4ConcurrentReadWrite-2 2 0 -100.00%\n BenchmarkTCP6ConcurrentReadWrite-2 7 0 -100.00%\n
R=dvyukov, minux.ma, dave, bradfitz, alex.brainman
CC=golang-dev
https://golang.org/cl/8264043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cb3b292201861b8052c665ccad6cf12ff0c8d839
元コミット内容
net: enable runtime-integrated network pollster on freebsd, openbsd
Fixes #5199.
Benchmark results on freebsd/amd64 (virtual machine):
benchmark old ns/op new ns/op delta
BenchmarkTCP4OneShot-2 184566 187164 +1.41%
BenchmarkTCP4OneShotTimeout-2 215558 187722 -12.91%
BenchmarkTCP4Persistent-2 59686 41294 -30.81%
BenchmarkTCP4PersistentTimeout-2 60692 39974 -34.14%
BenchmarkTCP6OneShot-2 226595 223688 -1.28%
BenchmarkTCP6OneShotTimeout-2 253144 225161 -11.05%
BenchmarkTCP6Persistent-2 69157 55605 -19.60%
BenchmarkTCP6PersistentTimeout-2 70426 53805 -23.60%
BenchmarkTCP4ConcurrentReadWrite-2 53878 56087 +4.10%
BenchmarkTCP6ConcurrentReadWrite-2 66538 68190 +2.48%
benchmark old allocs new allocs delta
BenchmarkTCP4OneShot-2 39 36 -7.69%
BenchmarkTCP4OneShotTimeout-2 42 36 -14.29%
BenchmarkTCP4Persistent-2 1 0 -100.00%
BenchmarkTCP4PersistentTimeout-2 1 0 -100.00%
BenchmarkTCP6OneShot-2 41 36 -12.20%
BenchmarkTCP6OneShotTimeout-2 43 36 -16.28%
BenchmarkTCP6Persistent-2 1 0 -100.00%
BenchmarkTCP6PersistentTimeout-2 1 0 -100.00%
BenchmarkTCP4ConcurrentReadWrite-2 0 0 n/a%
BenchmarkTCP6ConcurrentReadWrite-2 0 0 n/a%
benchmark old bytes new bytes delta
BenchmarkTCP4OneShot-2 3084 2544 -17.51%
BenchmarkTCP4OneShotTimeout-2 3129 2519 -19.50%
BenchmarkTCP4Persistent-2 30 0 -100.00%
BenchmarkTCP4PersistentTimeout-2 31 0 -100.00%
BenchmarkTCP6OneShot-2 3297 2660 -19.32%
BenchmarkTCP6OneShotTimeout-2 3306 2655 -19.69%
BenchmarkTCP6Persistent-2 31 0 -100.00%
BenchmarkTCP6PersistentTimeout-2 29 0 -100.00%
BenchmarkTCP4ConcurrentReadWrite-2 2 0 -100.00%
BenchmarkTCP6ConcurrentReadWrite-2 7 0 -100.00%
R=dvyukov, minux.ma, dave, bradfitz, alex.brainman
CC=golang-dev
https://golang.org/cl/8264043
変更の背景
このコミットの背景には、Go言語のネットワークI/O処理における効率性の向上が挙げられます。特に、FreeBSDやOpenBSDといったBSD系のOSにおいて、Goランタイムが提供する高度なネットワークポーリング機構を最大限に活用できていないという課題がありました。
Go言語のランタイムは、ノンブロッキングI/Oとイベント駆動型プログラミングを効率的に実現するために、OSが提供するI/O多重化メカニズム(Linuxのepoll、macOS/BSDのkqueueなど)を内部的に利用しています。これにより、多数のネットワーク接続を少数のゴルーチンで効率的に処理することが可能になります。
しかし、特定のOS(この場合はFreeBSDとOpenBSD)では、これらの最適化が十分に適用されておらず、結果としてネットワークI/Oのパフォーマンスが他のOSに比べて劣る可能性がありました。コミットメッセージに記載されている「Fixes #5199」は、この問題に関連するGoのIssueトラッカーのエントリを示しており、FreeBSD環境でのネットワークパフォーマンスの低下が報告されていたことを示唆しています。
このコミットは、これらのOSでもランタイム統合型のネットワークポーラーを有効にすることで、ネットワークI/Oのレイテンシを削減し、スループットを向上させることを目的としています。特に、多数のコネクションを扱うサーバーアプリケーションなどにおいて、その効果が顕著に現れることが期待されます。
前提知識の解説
このコミットを理解するためには、以下の前提知識が役立ちます。
1. Go言語のランタイムとスケジューラ
Go言語は、独自のランタイムとスケジューラを持っています。これは、OSのネイティブスレッド(M: Machine)上で多数の軽量なゴルーチン(G: Goroutine)を効率的にスケジューリングし、実行するためのものです。ゴルーチンは、Goプログラムにおける並行処理の基本単位であり、非常に軽量であるため、数百万個のゴルーチンを同時に実行することも可能です。
Goランタイムは、ゴルーチンがI/O操作(特にネットワークI/O)でブロックされる際に、そのゴルーチンを一時停止し、他の実行可能なゴルーチンにCPUを割り当てます。I/O操作が完了すると、ランタイムはブロックされていたゴルーチンを再開します。この仕組みにより、I/O待ちによるCPUのアイドル時間を最小限に抑え、高い並行性を実現しています。
2. ネットワークポーラー(Network Pollster)
ネットワークポーラーは、GoランタイムがノンブロッキングI/Oを効率的に管理するための重要なコンポーネントです。これは、OSが提供するI/O多重化メカニズム(例: Linuxのepoll、macOS/BSDのkqueue、WindowsのIOCP)を抽象化し、Goランタイムに統合されています。
ポーラーの主な役割は以下の通りです。
- I/Oイベントの監視: 複数のファイルディスクリプタ(ネットワークソケットなど)に対して、読み取り可能、書き込み可能といったI/Oイベントが発生するのを監視します。
- ゴルーチンのブロック/アンブロック: I/O操作を待つゴルーチンをブロックし、イベントが発生した際にそのゴルーチンをアンブロックして実行キューに戻します。
- システムコールオーバーヘッドの削減: 多数のソケットに対して個別にブロッキングI/Oシステムコールを発行する代わりに、単一のI/O多重化システムコール(例:
epoll_wait
,kqueue
,select
/poll
)で複数のイベントを効率的に処理します。
3. +build
ディレクティブ(ビルドタグ)
Go言語では、ソースコードファイルの先頭に+build
ディレクティブを記述することで、条件付きコンパイルを行うことができます。これは、特定のOS、アーキテクチャ、またはカスタムタグが指定された場合にのみ、そのファイルをビルドに含めるための仕組みです。
構文は以下の通りです。
// +build tag1,tag2 tag3
- カンマ(
,
)はAND条件を表します。tag1,tag2
はtag1
とtag2
の両方が存在する場合にマッチします。 - スペースはOR条件を表します。
tag1 tag2
はtag1
またはtag2
のいずれかが存在する場合にマッチします。 !tag
はNOT条件を表します。!tag
はそのタグが存在しない場合にマッチします。
このコミットでは、+build
ディレクティブが変更されており、特定のOS(FreeBSD, OpenBSD)とアーキテクチャ(amd64, 386)の組み合わせで、どのネットワークポーラーの実装が使用されるかを制御しています。
4. ファイルディスクリプタ(File Descriptor, FD)
Unix系OSにおいて、ファイルディスクリプタは、ファイル、ソケット、パイプなどのI/Oリソースを識別するための整数値です。Go言語のネットワークパッケージは、これらのFDを抽象化し、Goランタイムのポーラーと連携して効率的なI/Oを実現しています。
技術的詳細
このコミットの技術的な核心は、Goランタイムのネットワークポーラーが、FreeBSDおよびOpenBSDシステムでどのように有効化されるかを制御するビルドタグの変更にあります。
Goのnet
パッケージには、異なるOSやアーキテクチャに対応するために、複数のネットワークポーラー実装が存在します。
fd_poll_runtime.go
: Goランタイムに統合された、高性能なネットワークポーラーの実装(epoll, kqueueなどを使用)。fd_poll_unix.go
: 従来のselect
/poll
ベースのポーラー、またはより基本的なUnix I/O操作を使用する実装。
以前のGoのビルド設定では、FreeBSDとOpenBSDはfd_poll_unix.go
を使用するように設定されていました。これは、これらのOSが提供するkqueue
のような高度なI/O多重化メカニズムが、Goランタイムのポーラーと完全に統合されていなかったか、あるいは特定のアーキテクチャ(例: ARM)での互換性の問題があったためと考えられます。
このコミットでは、+build
ディレクティブを変更することで、FreeBSDおよびOpenBSDの特定のアーキテクチャ(amd64
, 386
)において、より効率的なfd_poll_runtime.go
がビルドに含まれるようにしています。
具体的には、以下の変更が行われています。
-
src/pkg/net/fd_bsd.go
:- 変更前:
// +build freebsd netbsd openbsd
- 変更後:
// +build freebsd,arm netbsd
- この変更により、
fd_bsd.go
はFreeBSDのARMアーキテクチャとNetBSDでのみビルドされるようになります。これは、fd_bsd.go
がkqueueベースのポーラーの一般的なBSD実装を含んでいる可能性があり、FreeBSDのamd64
/386
ではより特化したfd_poll_runtime.go
を使用するように切り替える意図があると考えられます。
- 変更前:
-
src/pkg/net/fd_poll_runtime.go
:- 変更前:
// +build darwin linux windows
- 変更後:
// +build darwin freebsd,amd64 freebsd,386 linux openbsd windows
- この変更が最も重要です。
fd_poll_runtime.go
がビルドされる条件に、freebsd,amd64
、freebsd,386
、およびopenbsd
が追加されました。これにより、これらのOS/アーキテクチャの組み合わせで、Goランタイムに統合された高性能なネットワークポーラーが使用されるようになります。
- 変更前:
-
src/pkg/net/fd_poll_unix.go
:- 変更前:
// +build freebsd netbsd openbsd
- 変更後:
// +build freebsd,arm netbsd
fd_poll_unix.go
は、FreeBSDのARMアーキテクチャとNetBSDでのみビルドされるように変更されました。これは、fd_bsd.go
と同様に、FreeBSDのamd64
/386
およびOpenBSDがfd_poll_runtime.go
に移行したため、従来のfd_poll_unix.go
の適用範囲が狭められたことを意味します。
- 変更前:
これらの変更により、FreeBSD (amd64/386) と OpenBSD は、Goランタイムのスケジューラと密接に連携する、より効率的なネットワークポーラーを利用できるようになり、ネットワークI/Oのパフォーマンスが向上します。
コミットメッセージに記載されているベンチマーク結果は、この変更がもたらすパフォーマンス向上を明確に示しています。特に、BenchmarkTCP4Persistent
やBenchmarkTCP4PersistentTimeout
のような持続的な接続を伴うベンチマークでは、ns/op
(操作あたりのナノ秒)が大幅に減少し、allocs
(アロケーション数)とbytes
(割り当てられたバイト数)が100%削減されています。これは、ポーラーの効率化により、I/O操作におけるメモリ割り当てとガベージコレクションのオーバーヘッドが劇的に減少したことを示唆しています。
一方で、BenchmarkTCP4OneShot
やBenchmarkTCP4ConcurrentReadWrite
のように、単発または並行読み書きのベンチマークでは、ns/op
がわずかに増加しているものもあります。これは、ランタイム統合型ポーラーの初期化や管理にわずかなオーバーヘッドがある可能性、あるいは特定のシナリオでは従来のポーラーの方が効率的であった可能性を示唆していますが、全体としては持続的な接続における大幅な改善が優先されたと考えられます。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、Goソースコード内の+build
ディレクティブの修正に集約されます。
-
src/pkg/net/fd_bsd.go
--- a/src/pkg/net/fd_bsd.go +++ b/src/pkg/net/fd_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.\n -// +build freebsd netbsd openbsd +// +build freebsd,arm netbsd // Waiting for FDs via kqueue/kevent.
-
src/pkg/net/fd_poll_runtime.go
--- a/src/pkg/net/fd_poll_runtime.go +++ b/src/pkg/net/fd_poll_runtime.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.\n -// +build darwin linux windows +// +build darwin freebsd,amd64 freebsd,386 linux openbsd windows package net
-
src/pkg/net/fd_poll_unix.go
--- a/src/pkg/net/fd_poll_unix.go +++ b/src/pkg/net/fd_poll_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.\n -// +build freebsd netbsd openbsd +// +build freebsd,arm netbsd package net
コアとなるコードの解説
これらの変更は、Go言語のビルドシステムにおける条件付きコンパイルのメカニズムを利用して、特定のOSとアーキテクチャの組み合わせで、どのネットワークポーラーの実装がGoバイナリに含まれるかを制御しています。
-
src/pkg/net/fd_bsd.go
の変更:- 元の
+build freebsd netbsd openbsd
は、FreeBSD、NetBSD、OpenBSDのいずれかのOSでビルドされる場合にこのファイルを含めることを意味していました。 - 変更後の
+build freebsd,arm netbsd
は、FreeBSDかつARMアーキテクチャ、またはNetBSDの場合にのみこのファイルを含めることを意味します。 - これにより、FreeBSDの
amd64
や386
アーキテクチャ、およびOpenBSDでは、このファイル(おそらく一般的なBSD kqueue実装)がビルドから除外されることになります。
- 元の
-
src/pkg/net/fd_poll_runtime.go
の変更:- 元の
+build darwin linux windows
は、macOS (darwin)、Linux、Windowsでビルドされる場合にこのファイルを含めることを意味していました。このファイルは、Goランタイムに統合された高性能なポーラーの実装を含んでいます。 - 変更後の
+build darwin freebsd,amd64 freebsd,386 linux openbsd windows
は、既存のOSに加えて、FreeBSDのamd64
アーキテクチャ、FreeBSDの386
アーキテクチャ、およびOpenBSDでもこの高性能なポーラーがビルドに含まれるようにします。 - この変更が、FreeBSDとOpenBSDにおけるネットワークパフォーマンス向上の直接的な原因となります。これらのシステムが、より効率的なランタイム統合型ポーラーを利用できるようになるためです。
- 元の
-
src/pkg/net/fd_poll_unix.go
の変更:- このファイルの変更は、
fd_bsd.go
の変更と類似しており、fd_poll_unix.go
がビルドされる条件からFreeBSDのamd64
/386
およびOpenBSDが除外され、FreeBSDのARMアーキテクチャとNetBSDに限定されることを意味します。 - これは、これらのOS/アーキテクチャが
fd_poll_runtime.go
に移行したため、従来のfd_poll_unix.go
の実装が不要になったことを示しています。
- このファイルの変更は、
これらの変更は、Go言語のクロスプラットフォーム対応とパフォーマンス最適化戦略の一環として行われました。特定のOS/アーキテクチャの組み合わせに対して最適なI/O多重化メカニズムを選択し、Goランタイムのスケジューラと密接に連携させることで、ネットワークアプリケーションの効率と応答性を向上させています。
関連リンク
- Go Issue #5199: https://github.com/golang/go/issues/5199 (このコミットが修正したとされるIssue)
- Go Change List 8264043: https://golang.org/cl/8264043 (このコミットに対応するGoのコードレビューシステムのエントリ)
参考にした情報源リンク
- Go言語のビルドタグに関する公式ドキュメント: https://pkg.go.dev/cmd/go#hdr-Build_constraints
- Go言語のネットワークI/Oとランタイムに関する一般的な情報源(例: Goの内部動作に関するブログ記事やプレゼンテーション)
- epoll, kqueueなどのI/O多重化メカニズムに関するOSのドキュメントや解説記事。
- Go言語の
net
パッケージのソースコード(特にsrc/pkg/net/
ディレクトリ内のファイル)。 - Go言語のベンチマーク結果の解釈に関する情報。