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

[インデックス 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,tag2tag1tag2の両方が存在する場合にマッチします。
  • スペースはOR条件を表します。tag1 tag2tag1または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がビルドに含まれるようにしています。

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

  1. 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を使用するように切り替える意図があると考えられます。
  2. 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,amd64freebsd,386、およびopenbsdが追加されました。これにより、これらのOS/アーキテクチャの組み合わせで、Goランタイムに統合された高性能なネットワークポーラーが使用されるようになります。
  3. 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のパフォーマンスが向上します。

コミットメッセージに記載されているベンチマーク結果は、この変更がもたらすパフォーマンス向上を明確に示しています。特に、BenchmarkTCP4PersistentBenchmarkTCP4PersistentTimeoutのような持続的な接続を伴うベンチマークでは、ns/op(操作あたりのナノ秒)が大幅に減少し、allocs(アロケーション数)とbytes(割り当てられたバイト数)が100%削減されています。これは、ポーラーの効率化により、I/O操作におけるメモリ割り当てとガベージコレクションのオーバーヘッドが劇的に減少したことを示唆しています。

一方で、BenchmarkTCP4OneShotBenchmarkTCP4ConcurrentReadWriteのように、単発または並行読み書きのベンチマークでは、ns/opがわずかに増加しているものもあります。これは、ランタイム統合型ポーラーの初期化や管理にわずかなオーバーヘッドがある可能性、あるいは特定のシナリオでは従来のポーラーの方が効率的であった可能性を示唆していますが、全体としては持続的な接続における大幅な改善が優先されたと考えられます。

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

このコミットにおけるコアとなるコードの変更は、Goソースコード内の+buildディレクティブの修正に集約されます。

  1. 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.
    
  2. 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
    
  3. 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のamd64386アーキテクチャ、および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言語のビルドタグに関する公式ドキュメント: https://pkg.go.dev/cmd/go#hdr-Build_constraints
  • Go言語のネットワークI/Oとランタイムに関する一般的な情報源(例: Goの内部動作に関するブログ記事やプレゼンテーション)
  • epoll, kqueueなどのI/O多重化メカニズムに関するOSのドキュメントや解説記事。
  • Go言語のnetパッケージのソースコード(特にsrc/pkg/net/ディレクトリ内のファイル)。
  • Go言語のベンチマーク結果の解釈に関する情報。