[インデックス 17470] ファイルの概要
このコミットは、Go言語の標準ライブラリである compress/flate パッケージのテストファイル src/pkg/compress/flate/reader_test.go に変更を加えています。具体的には、ベンチマークテストにおいて bytes.NewBuffer の代わりに bytes.NewReader を使用するように修正し、さらにベンチマーク結果にメモリ割り当て(アロケーション)の情報を報告するように変更しています。
コミット
commit fca660892db526f86b9d113e58e292c27583b6a7
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Wed Sep 4 15:31:46 2013 -0700
compress/flate: use bytes.NewReader instead of NewBuffer in test
Also, report allocations in benchmark.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/13410044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fca660892db526f86b9d113e58e292c27583b6a7
元コミット内容
compress/flate: use bytes.NewReader instead of NewBuffer in test
Also, report allocations in benchmark.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/13410044
変更の背景
このコミットの背景には、Go言語のベンチマークテストの精度と有用性を向上させる目的があります。
-
bytes.NewBufferからbytes.NewReaderへの変更:bytes.Bufferは可変長のバイトスライスを扱うための型で、主に書き込み操作(Writeメソッドなど)によって内部バッファが拡張される可能性があります。一方、bytes.Readerは固定長のバイトスライスを読み込むための型で、内部バッファの拡張は発生しません。ベンチマークテストにおいて、入力データが固定であるにもかかわらずbytes.NewBufferを使用すると、内部で不要なメモリ割り当てやコピーが発生し、ベンチマーク結果にノイズが混入する可能性があります。特に、io.Copyのような操作でbytes.Bufferをソースとして使用する場合、bytes.Bufferはio.Readerインターフェースを満たしますが、その実装がbytes.Readerよりも効率的でない場合があります。この変更は、ベンチマークの対象となるcompress/flateパッケージ自体の性能をより正確に測定するために、テストハーネス(テストコード)が引き起こすオーバーヘッドを最小限に抑えることを目的としています。 -
ベンチマークでのメモリ割り当て報告 (
b.ReportAllocs()): Goのベンチマークは通常、実行時間(ops/sec)を測定しますが、b.ReportAllocs()を呼び出すことで、ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数も報告されるようになります。これは、特にガベージコレクション(GC)の影響を受けやすいGo言語において、パフォーマンスチューニングの重要な指標となります。実行時間だけでなく、メモリ割り当ての状況を把握することで、より効率的なコードパスを見つけ出し、GCの負荷を軽減する改善を行うための手がかりを得ることができます。この変更は、compress/flateパッケージのデコード処理がどれだけメモリを効率的に使用しているかを評価するために追加されました。
要するに、このコミットは、compress/flate パッケージのベンチマークテストをより正確かつ包括的にすることで、将来的な性能改善のための基盤を強化することを目的としています。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念と標準ライブラリに関する知識が必要です。
-
compress/flateパッケージ:compress/flateパッケージは、DEFLATEアルゴリズム(RFC 1951で定義)を実装したGo言語の標準ライブラリです。DEFLATEは、Zlibやgzipなどの圧縮形式の基盤となるデータ圧縮アルゴリズムです。このパッケージは、データの圧縮(エンコード)と解凍(デコード)機能を提供します。このコミットでは、主にデコード(解凍)のベンチマークテストが対象となっています。 -
bytesパッケージ:bytesパッケージは、バイトスライスを操作するためのユーティリティ関数と型を提供します。bytes.Buffer: 可変長のバイトバッファを実装する型です。io.Readerおよびio.Writerインターフェースを実装しており、バイトスライスへの書き込みやバイトスライスからの読み込みが可能です。内部的には必要に応じてバッファが拡張されます。bytes.Reader: 固定長のバイトスライスから読み込むための型です。io.Reader,io.ReaderAt,io.Seeker,io.ByteReader,io.RuneReaderインターフェースを実装しています。内部バッファは固定であり、拡張されることはありません。
-
ioパッケージとio.Copy:ioパッケージは、I/Oプリミティブ(Reader、Writerなど)を定義するGo言語の基本的なパッケージです。io.Readerインターフェース:Read(p []byte) (n int, err error)メソッドを持つインターフェースで、データソースからの読み込みを抽象化します。io.Writerインターフェース:Write(p []byte) (n int, err error)メソッドを持つインターフェースで、データシンクへの書き込みを抽象化します。io.Copy(dst io.Writer, src io.Reader) (written int64, err error):srcからデータを読み込み、dstに書き込むユーティリティ関数です。srcがio.WriterToインターフェースを実装している場合、そのWriteToメソッドが使用され、dstがio.ReaderFromインターフェースを実装している場合、そのReadFromメソッドが使用されます。これにより、効率的なデータ転送が可能です。
-
testingパッケージとベンチマーク:testingパッケージは、Go言語のテストとベンチマークをサポートするための機能を提供します。*testing.B: ベンチマーク関数に渡される型で、ベンチマークの実行を制御し、結果を報告するためのメソッドを提供します。b.ReportAllocs(): ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数を報告するように設定します。このメソッドは、ベンチマーク関数の開始時に一度だけ呼び出す必要があります。b.StopTimer()/b.StartTimer(): ベンチマークの計測時間を一時停止/再開します。セットアップやクリーンアップなど、ベンチマーク対象外の処理の時間を計測から除外するために使用されます。b.SetBytes(n int64): 1回の操作で処理されるバイト数を設定します。これにより、ベンチマーク結果が「操作/秒」だけでなく「バイト/秒」としても報告されるようになります。b.N: ベンチマーク関数が実行されるイテレーション回数です。testingパッケージが自動的に調整し、統計的に有意な結果が得られるようにします。
-
runtime.GC():runtimeパッケージは、Goランタイムとの相互作用を可能にする関数を提供します。runtime.GC()は、ガベージコレクタを強制的に実行します。ベンチマークにおいて、GCの影響を均一にするためや、特定の処理の直後にメモリをクリーンアップするために使用されることがあります。
技術的詳細
このコミットの技術的な核心は、bytes.NewBuffer と bytes.NewReader の使い分け、およびベンチマークにおけるメモリ割り当ての重要性にあります。
bytes.NewBuffer と bytes.NewReader の違いとベンチマークへの影響
-
bytes.NewBuffer(buf []byte): この関数は、与えられたバイトスライスbufを初期内容とするbytes.Bufferを作成します。bytes.Bufferは内部に可変長のバイトスライスを持っており、書き込み操作(例:io.Copyのsrcがbytes.Bufferの場合、bytes.BufferのReadメソッドが呼ばれる)によって、必要に応じて内部バッファが拡張される可能性があります。 ベンチマークの文脈では、bytes.NewBufferを使用すると、たとえ読み込み専用の操作であっても、bytes.Bufferの内部実装がbytes.Readerよりも複雑であるため、わずかながらオーバーヘッドが発生する可能性があります。特に、io.Copyのような操作では、bytes.Bufferがio.Readerインターフェースを満たすために、内部で追加のチェックや処理が行われることが考えられます。 -
bytes.NewReader(buf []byte): この関数は、与えられたバイトスライスbufを読み込み専用のデータソースとするbytes.Readerを作成します。bytes.Readerは内部バッファを拡張することなく、常に固定のバイトスライスから読み込みを行います。 ベンチマークの文脈では、bytes.NewReaderは読み込み専用の操作に特化しているため、bytes.NewBufferよりも効率的です。不要なメモリ割り当てやバッファの拡張ロジックがないため、より純粋な読み込み性能を測定できます。io.Copyのsrcとしてbytes.NewReaderを使用する場合、bytes.Readerはio.Readerインターフェースを効率的に実装しており、特にio.WriterToインターフェースも実装しているため、io.Copyが内部で最適化されたパス(WriteToメソッドの利用)を選択する可能性が高く、これによりコピー操作全体の効率が向上します。
この変更は、compress/flate のデコード処理のベンチマークにおいて、入力データの準備段階でのオーバーヘッドを削減し、より正確なデコード性能を測定することを目的としています。
b.ReportAllocs() の重要性
Go言語では、メモリ割り当て(アロケーション)はガベージコレクション(GC)のトリガーとなり、GCはプログラムの実行を一時停止させる可能性があります。したがって、メモリ割り当ての回数と量が少ないほど、GCの頻度と時間が減少し、全体的なパフォーマンスが向上する傾向があります。
b.ReportAllocs() をベンチマークに追加することで、以下の情報が得られます。
allocs/op: 1回の操作あたりのメモリ割り当て回数。B/op: 1回の操作あたりのメモリ割り当てバイト数。
これらの指標は、コードがどれだけメモリ効率が良いかを示します。例えば、あるベンチマークで allocs/op が高い場合、それはループ内でオブジェクトが頻繁に作成されていることを示唆しており、オブジェクトプールの利用や、スライス/マップの事前割り当てなどによって改善できる可能性があります。
このコミットでは、compress/flate のデコード処理がどれだけメモリを効率的に使用しているかを評価するために b.ReportAllocs() が追加されました。これにより、将来的にデコード処理のメモリ効率を改善するための具体的な目標設定や、改善効果の検証が可能になります。
コアとなるコードの変更箇所
--- a/src/pkg/compress/flate/reader_test.go
+++ b/src/pkg/compress/flate/reader_test.go
@@ -37,6 +37,7 @@ var testfiles = []string{
}
func benchmarkDecode(b *testing.B, testfile, level, n int) {
+ b.ReportAllocs()
b.StopTimer()
b.SetBytes(int64(n))
buf0, err := ioutil.ReadFile(testfiles[testfile])
@@ -55,7 +56,7 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
}
- io.Copy(w, bytes.NewBuffer(buf0))
+ io.Copy(w, bytes.NewReader(buf0))
}
w.Close()
buf1 := compressed.Bytes()
@@ -63,7 +64,7 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) {
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
- io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1)))
+ io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
}
}
コアとなるコードの解説
このコミットでは、src/pkg/compress/flate/reader_test.go ファイル内の benchmarkDecode 関数に3つの変更が加えられています。
-
b.ReportAllocs()の追加:func benchmarkDecode(b *testing.B, testfile, level, n int) { + b.ReportAllocs() b.StopTimer() // ... }benchmarkDecode関数の冒頭にb.ReportAllocs()が追加されました。これにより、このベンチマークを実行する際に、Goのテストフレームワークが実行時間だけでなく、ベンチマーク中に発生したメモリ割り当ての回数と合計バイト数も計測し、結果として報告するようになります。これは、compress/flateのデコード処理のメモリ効率を評価するための重要な指標となります。 -
io.Copyのソースをbytes.NewBufferからbytes.NewReaderへ変更 (1回目):- io.Copy(w, bytes.NewBuffer(buf0)) + io.Copy(w, bytes.NewReader(buf0))これは、圧縮前のデータ
buf0をflate.Writer(w) にコピーする部分の変更です。以前はbytes.NewBuffer(buf0)を使用していましたが、これをbytes.NewReader(buf0)に変更しました。buf0はioutil.ReadFileで読み込まれた固定長のバイトスライスであり、読み込み専用のデータソースとして使用されます。このような場合、bytes.NewReaderを使用する方がbytes.NewBufferよりも効率的です。bytes.NewReaderは内部でバッファの拡張を考慮する必要がなく、読み込みに特化しているため、ベンチマークのオーバーヘッドを削減し、より正確な圧縮処理の性能を測定できます。 -
io.Copyのソースをbytes.NewBufferからbytes.NewReaderへ変更 (2回目):- io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1))) + io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))これは、圧縮されたデータ
buf1をflate.Reader(NewReader(bytes.NewBuffer(buf1))) を通してioutil.Discard(書き込まれたデータを破棄するio.Writer) にコピーする部分の変更です。ここでも、bytes.NewBuffer(buf1)がbytes.NewReader(buf1)に変更されました。buf1もまた、圧縮された固定長のバイトスライスであり、デコード処理の入力として使用されます。ここでも、読み込み専用のデータソースとしてbytes.NewReaderを使用することで、デコード処理のベンチマークにおける入力準備のオーバーヘッドを最小限に抑え、より純粋なデコード性能を測定することが可能になります。
これらの変更は、compress/flate パッケージのベンチマークテストの精度と有用性を向上させることを目的としています。特に、メモリ割り当ての報告は、将来的な性能最適化のための重要な情報を提供します。
関連リンク
- Go CL 13410044: https://golang.org/cl/13410044
参考にした情報源リンク
- Go言語の
bytesパッケージドキュメント: https://pkg.go.dev/bytes - Go言語の
ioパッケージドキュメント: https://pkg.go.dev/io - Go言語の
testingパッケージドキュメント: https://pkg.go.dev/testing - Go言語の
compress/flateパッケージドキュメント: https://pkg.go.dev/compress/flate - Go言語のベンチマークに関する公式ドキュメントやブログ記事 (一般的な知識として参照)
- The Go Programming Language Blog: Benchmarking Go Programs: https://go.dev/blog/benchmarking
- Go Wiki: Benchmarking: https://go.dev/wiki/Benchmarking
- RFC 1951 - DEFLATE Compressed Data Format Specification version 1.3: https://www.rfc-editor.org/rfc/rfc1951
- Go言語のガベージコレクションに関する情報 (一般的な知識として参照)
- Go言語のメモリ管理とGCの仕組みに関する記事など# [インデックス 17470] ファイルの概要
このコミットは、Go言語の標準ライブラリである compress/flate パッケージのテストファイル src/pkg/compress/flate/reader_test.go に変更を加えています。具体的には、ベンチマークテストにおいて bytes.NewBuffer の代わりに bytes.NewReader を使用するように修正し、さらにベンチマーク結果にメモリ割り当て(アロケーション)の情報を報告するように変更しています。
コミット
commit fca660892db526f86b9d113e58e292c27583b6a7
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Wed Sep 4 15:31:46 2013 -0700
compress/flate: use bytes.NewReader instead of NewBuffer in test
Also, report allocations in benchmark.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/13410044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fca660892db526f86b9d113e58e292c27583b6a7
元コミット内容
compress/flate: use bytes.NewReader instead of NewBuffer in test
Also, report allocations in benchmark.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/13410044
変更の背景
このコミットの背景には、Go言語のベンチマークテストの精度と有用性を向上させる目的があります。
-
bytes.NewBufferからbytes.NewReaderへの変更:bytes.Bufferは可変長のバイトスライスを扱うための型で、主に書き込み操作(Writeメソッドなど)によって内部バッファが拡張される可能性があります。一方、bytes.Readerは固定長のバイトスライスを読み込むための型で、内部バッファの拡張は発生しません。ベンチマークテストにおいて、入力データが固定であるにもかかわらずbytes.NewBufferを使用すると、内部で不要なメモリ割り当てやコピーが発生し、ベンチマーク結果にノイズが混入する可能性があります。特に、io.Copyのような操作でbytes.Bufferをソースとして使用する場合、bytes.Bufferはio.Readerインターフェースを満たしますが、その実装がbytes.Readerよりも効率的でない場合があります。この変更は、ベンチマークの対象となるcompress/flateパッケージ自体の性能をより正確に測定するために、テストハーネス(テストコード)が引き起こすオーバーヘッドを最小限に抑えることを目的としています。 -
ベンチマークでのメモリ割り当て報告 (
b.ReportAllocs()): Goのベンチマークは通常、実行時間(ops/sec)を測定しますが、b.ReportAllocs()を呼び出すことで、ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数も報告されるようになります。これは、特にガベージコレクション(GC)の影響を受けやすいGo言語において、パフォーマンスチューニングの重要な指標となります。実行時間だけでなく、メモリ割り当ての状況を把握することで、より効率的なコードパスを見つけ出し、GCの負荷を軽減する改善を行うための手がかりを得ることができます。この変更は、compress/flateパッケージのデコード処理がどれだけメモリを効率的に使用しているかを評価するために追加されました。
要するに、このコミットは、compress/flate パッケージのベンチマークテストをより正確かつ包括的にすることで、将来的な性能改善のための基盤を強化することを目的としています。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念と標準ライブラリに関する知識が必要です。
-
compress/flateパッケージ:compress/flateパッケージは、DEFLATEアルゴリズム(RFC 1951で定義)を実装したGo言語の標準ライブラリです。DEFLATEは、Zlibやgzipなどの圧縮形式の基盤となるデータ圧縮アルゴリズムです。このパッケージは、データの圧縮(エンコード)と解凍(デコード)機能を提供します。このコミットでは、主にデコード(解凍)のベンチマークテストが対象となっています。 -
bytesパッケージ:bytesパッケージは、バイトスライスを操作するためのユーティリティ関数と型を提供します。bytes.Buffer: 可変長のバイトバッファを実装する型です。io.Readerおよびio.Writerインターフェースを実装しており、バイトスライスへの書き込みやバイトスライスからの読み込みが可能です。内部的には必要に応じてバッファが拡張されます。bytes.Reader: 固定長のバイトスライスから読み込むための型です。io.Reader,io.ReaderAt,io.Seeker,io.ByteReader,io.RuneReaderインターフェースを実装しています。内部バッファは固定であり、拡張されることはありません。
-
ioパッケージとio.Copy:ioパッケージは、I/Oプリミティブ(Reader、Writerなど)を定義するGo言語の基本的なパッケージです。io.Readerインターフェース:Read(p []byte) (n int, err error)メソッドを持つインターフェースで、データソースからの読み込みを抽象化します。io.Writerインターフェース:Write(p []byte) (n int, err error)メソッドを持つインターフェースで、データシンクへの書き込みを抽象化します。io.Copy(dst io.Writer, src io.Reader) (written int64, err error):srcからデータを読み込み、dstに書き込むユーティリティ関数です。srcがio.WriterToインターフェースを実装している場合、そのWriteToメソッドが使用され、dstがio.ReaderFromインターフェースを実装している場合、そのReadFromメソッドが使用されます。これにより、効率的なデータ転送が可能です。
-
testingパッケージとベンチマーク:testingパッケージは、Go言語のテストとベンチマークをサポートするための機能を提供します。*testing.B: ベンチマーク関数に渡される型で、ベンチマークの実行を制御し、結果を報告するためのメソッドを提供します。b.ReportAllocs(): ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数を報告するように設定します。このメソッドは、ベンチマーク関数の開始時に一度だけ呼び出す必要があります。b.StopTimer()/b.StartTimer(): ベンチマークの計測時間を一時停止/再開します。セットアップやクリーンアップなど、ベンチマーク対象外の処理の時間を計測から除外するために使用されます。b.SetBytes(n int64): 1回の操作で処理されるバイト数を設定します。これにより、ベンチマーク結果が「操作/秒」だけでなく「バイト/秒」としても報告されるようになります。b.N: ベンチマーク関数が実行されるイテレーション回数です。testingパッケージが自動的に調整し、統計的に有意な結果が得られるようにします。
-
runtime.GC():runtimeパッケージは、Goランタイムとの相互作用を可能にする関数を提供します。runtime.GC()は、ガベージコレクタを強制的に実行します。ベンチマークにおいて、GCの影響を均一にするためや、特定の処理の直後にメモリをクリーンアップするために使用されることがあります。
技術的詳細
このコミットの技術的な核心は、bytes.NewBuffer と bytes.NewReader の使い分け、およびベンチマークにおけるメモリ割り当ての重要性にあります。
bytes.NewBuffer と bytes.NewReader の違いとベンチマークへの影響
-
bytes.NewBuffer(buf []byte): この関数は、与えられたバイトスライスbufを初期内容とするbytes.Bufferを作成します。bytes.Bufferは内部に可変長のバイトスライスを持っており、書き込み操作(例:io.Copyのsrcがbytes.Bufferの場合、bytes.BufferのReadメソッドが呼ばれる)によって、必要に応じて内部バッファが拡張される可能性があります。 ベンチマークの文脈では、bytes.NewBufferを使用すると、たとえ読み込み専用の操作であっても、bytes.Bufferの内部実装がbytes.Readerよりも複雑であるため、わずかながらオーバーヘッドが発生する可能性があります。特に、io.Copyのような操作では、bytes.Bufferがio.Readerインターフェースを満たすために、内部で追加のチェックや処理が行われることが考えられます。 -
bytes.NewReader(buf []byte): この関数は、与えられたバイトスライスbufを読み込み専用のデータソースとするbytes.Readerを作成します。bytes.Readerは内部バッファを拡張することなく、常に固定のバイトスライスから読み込みを行います。 ベンチマークの文脈では、bytes.NewReaderは読み込み専用の操作に特化しているため、bytes.NewBufferよりも効率的です。不要なメモリ割り当てやバッファの拡張ロジックがないため、より純粋な読み込み性能を測定できます。io.Copyのsrcとしてbytes.NewReaderを使用する場合、bytes.Readerはio.Readerインターフェースを効率的に実装しており、特にio.WriterToインターフェースも実装しているため、io.Copyが内部で最適化されたパス(WriteToメソッドの利用)を選択する可能性が高く、これによりコピー操作全体の効率が向上します。
この変更は、compress/flate のデコード処理のベンチマークにおいて、入力データの準備段階でのオーバーヘッドを削減し、より正確なデコード性能を測定することを目的としています。
b.ReportAllocs() の重要性
Go言語では、メモリ割り当て(アロケーション)はガベージコレクション(GC)のトリガーとなり、GCはプログラムの実行を一時停止させる可能性があります。したがって、メモリ割り当ての回数と量が少ないほど、GCの頻度と時間が減少し、全体的なパフォーマンスが向上する傾向があります。
b.ReportAllocs() をベンチマークに追加することで、以下の情報が得られます。
allocs/op: 1回の操作あたりのメモリ割り当て回数。B/op: 1回の操作あたりのメモリ割り当てバイト数。
これらの指標は、コードがどれだけメモリ効率が良いかを示します。例えば、あるベンチマークで allocs/op が高い場合、それはループ内でオブジェクトが頻繁に作成されていることを示唆しており、オブジェクトプールの利用や、スライス/マップの事前割り当てなどによって改善できる可能性があります。
このコミットでは、compress/flate のデコード処理がどれだけメモリを効率的に使用しているかを評価するために b.ReportAllocs() が追加されました。これにより、将来的にデコード処理のメモリ効率を改善するための具体的な目標設定や、改善効果の検証が可能になります。
コアとなるコードの変更箇所
--- a/src/pkg/compress/flate/reader_test.go
+++ b/src/pkg/compress/flate/reader_test.go
@@ -37,6 +37,7 @@ var testfiles = []string{
}
func benchmarkDecode(b *testing.B, testfile, level, n int) {
+ b.ReportAllocs()
b.StopTimer()
b.SetBytes(int64(n))
buf0, err := ioutil.ReadFile(testfiles[testfile])
@@ -55,7 +56,7 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
}
- io.Copy(w, bytes.NewBuffer(buf0))
+ io.Copy(w, bytes.NewReader(buf0))
}
w.Close()
buf1 := compressed.Bytes()
@@ -63,7 +64,7 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) {
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
- io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1)))
+ io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
}
}
コアとなるコードの解説
このコミットでは、src/pkg/compress/flate/reader_test.go ファイル内の benchmarkDecode 関数に3つの変更が加えられています。
-
b.ReportAllocs()の追加:func benchmarkDecode(b *testing.B, testfile, level, n int) { + b.ReportAllocs() b.StopTimer() // ... }benchmarkDecode関数の冒頭にb.ReportAllocs()が追加されました。これにより、このベンチマークを実行する際に、Goのテストフレームワークが実行時間だけでなく、ベンチマーク中に発生したメモリ割り当ての回数と合計バイト数も計測し、結果として報告するようになります。これは、compress/flateのデコード処理のメモリ効率を評価するための重要な指標となります。 -
io.Copyのソースをbytes.NewBufferからbytes.NewReaderへ変更 (1回目):- io.Copy(w, bytes.NewBuffer(buf0)) + io.Copy(w, bytes.NewReader(buf0))これは、圧縮前のデータ
buf0をflate.Writer(w) にコピーする部分の変更です。以前はbytes.NewBuffer(buf0)を使用していましたが、これをbytes.NewReader(buf0)に変更しました。buf0はioutil.ReadFileで読み込まれた固定長のバイトスライスであり、読み込み専用のデータソースとして使用されます。このような場合、bytes.NewReaderを使用する方がbytes.NewBufferよりも効率的です。bytes.NewReaderは内部でバッファの拡張を考慮する必要がなく、読み込みに特化しているため、ベンチマークのオーバーヘッドを削減し、より正確な圧縮処理の性能を測定できます。 -
io.Copyのソースをbytes.NewBufferからbytes.NewReaderへ変更 (2回目):- io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1))) + io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))これは、圧縮されたデータ
buf1をflate.Reader(NewReader(bytes.NewBuffer(buf1))) を通してioutil.Discard(書き込まれたデータを破棄するio.Writer) にコピーする部分の変更です。ここでも、bytes.NewBuffer(buf1)がbytes.NewReader(buf1)に変更されました。buf1もまた、圧縮された固定長のバイトスライスであり、デコード処理の入力として使用されます。ここでも、読み込み専用のデータソースとしてbytes.NewReaderを使用することで、デコード処理のベンチマークにおける入力準備のオーバーヘッドを最小限に抑え、より純粋なデコード性能を測定することが可能になります。
これらの変更は、compress/flate パッケージのベンチマークテストの精度と有用性を向上させることを目的としています。特に、メモリ割り当ての報告は、将来的な性能最適化のための重要な情報を提供します。
関連リンク
- Go CL 13410044: https://golang.org/cl/13410044
参考にした情報源リンク
- Go言語の
bytesパッケージドキュメント: https://pkg.go.dev/bytes - Go言語の
ioパッケージドキュメント: https://pkg.go.dev/io - Go言語の
testingパッケージドキュメント: https://pkg.go.dev/testing - Go言語の
compress/flateパッケージドキュメント: https://pkg.go.dev/compress/flate - Go言語のベンチマークに関する公式ドキュメントやブログ記事 (一般的な知識として参照)
- The Go Programming Language Blog: Benchmarking Go Programs: https://go.dev/blog/benchmarking
- Go Wiki: Benchmarking: https://go.dev/wiki/Benchmarking
- RFC 1951 - DEFLATE Compressed Data Format Specification version 1.3: https://www.rfc-editor.org/rfc/rfc1951
- Go言語のガベージコレクションに関する情報 (一般的な知識として参照)
- Go言語のメモリ管理とGCの仕組みに関する記事など