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

[インデックス 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言語のベンチマークテストの精度と有用性を向上させる目的があります。

  1. bytes.NewBuffer から bytes.NewReader への変更: bytes.Buffer は可変長のバイトスライスを扱うための型で、主に書き込み操作(Write メソッドなど)によって内部バッファが拡張される可能性があります。一方、bytes.Reader は固定長のバイトスライスを読み込むための型で、内部バッファの拡張は発生しません。ベンチマークテストにおいて、入力データが固定であるにもかかわらず bytes.NewBuffer を使用すると、内部で不要なメモリ割り当てやコピーが発生し、ベンチマーク結果にノイズが混入する可能性があります。特に、io.Copy のような操作で bytes.Buffer をソースとして使用する場合、bytes.Bufferio.Reader インターフェースを満たしますが、その実装が bytes.Reader よりも効率的でない場合があります。この変更は、ベンチマークの対象となる compress/flate パッケージ自体の性能をより正確に測定するために、テストハーネス(テストコード)が引き起こすオーバーヘッドを最小限に抑えることを目的としています。

  2. ベンチマークでのメモリ割り当て報告 (b.ReportAllocs()): Goのベンチマークは通常、実行時間(ops/sec)を測定しますが、b.ReportAllocs() を呼び出すことで、ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数も報告されるようになります。これは、特にガベージコレクション(GC)の影響を受けやすいGo言語において、パフォーマンスチューニングの重要な指標となります。実行時間だけでなく、メモリ割り当ての状況を把握することで、より効率的なコードパスを見つけ出し、GCの負荷を軽減する改善を行うための手がかりを得ることができます。この変更は、compress/flate パッケージのデコード処理がどれだけメモリを効率的に使用しているかを評価するために追加されました。

要するに、このコミットは、compress/flate パッケージのベンチマークテストをより正確かつ包括的にすることで、将来的な性能改善のための基盤を強化することを目的としています。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念と標準ライブラリに関する知識が必要です。

  1. compress/flate パッケージ: compress/flate パッケージは、DEFLATEアルゴリズム(RFC 1951で定義)を実装したGo言語の標準ライブラリです。DEFLATEは、Zlibやgzipなどの圧縮形式の基盤となるデータ圧縮アルゴリズムです。このパッケージは、データの圧縮(エンコード)と解凍(デコード)機能を提供します。このコミットでは、主にデコード(解凍)のベンチマークテストが対象となっています。

  2. bytes パッケージ: bytes パッケージは、バイトスライスを操作するためのユーティリティ関数と型を提供します。

    • bytes.Buffer: 可変長のバイトバッファを実装する型です。io.Reader および io.Writer インターフェースを実装しており、バイトスライスへの書き込みやバイトスライスからの読み込みが可能です。内部的には必要に応じてバッファが拡張されます。
    • bytes.Reader: 固定長のバイトスライスから読み込むための型です。io.Reader, io.ReaderAt, io.Seeker, io.ByteReader, io.RuneReader インターフェースを実装しています。内部バッファは固定であり、拡張されることはありません。
  3. 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 に書き込むユーティリティ関数です。srcio.WriterTo インターフェースを実装している場合、その WriteTo メソッドが使用され、dstio.ReaderFrom インターフェースを実装している場合、その ReadFrom メソッドが使用されます。これにより、効率的なデータ転送が可能です。
  4. testing パッケージとベンチマーク: testing パッケージは、Go言語のテストとベンチマークをサポートするための機能を提供します。

    • *testing.B: ベンチマーク関数に渡される型で、ベンチマークの実行を制御し、結果を報告するためのメソッドを提供します。
    • b.ReportAllocs(): ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数を報告するように設定します。このメソッドは、ベンチマーク関数の開始時に一度だけ呼び出す必要があります。
    • b.StopTimer() / b.StartTimer(): ベンチマークの計測時間を一時停止/再開します。セットアップやクリーンアップなど、ベンチマーク対象外の処理の時間を計測から除外するために使用されます。
    • b.SetBytes(n int64): 1回の操作で処理されるバイト数を設定します。これにより、ベンチマーク結果が「操作/秒」だけでなく「バイト/秒」としても報告されるようになります。
    • b.N: ベンチマーク関数が実行されるイテレーション回数です。testing パッケージが自動的に調整し、統計的に有意な結果が得られるようにします。
  5. runtime.GC(): runtime パッケージは、Goランタイムとの相互作用を可能にする関数を提供します。runtime.GC() は、ガベージコレクタを強制的に実行します。ベンチマークにおいて、GCの影響を均一にするためや、特定の処理の直後にメモリをクリーンアップするために使用されることがあります。

技術的詳細

このコミットの技術的な核心は、bytes.NewBufferbytes.NewReader の使い分け、およびベンチマークにおけるメモリ割り当ての重要性にあります。

bytes.NewBufferbytes.NewReader の違いとベンチマークへの影響

  • bytes.NewBuffer(buf []byte): この関数は、与えられたバイトスライス buf を初期内容とする bytes.Buffer を作成します。bytes.Buffer は内部に可変長のバイトスライスを持っており、書き込み操作(例: io.Copysrcbytes.Buffer の場合、bytes.BufferRead メソッドが呼ばれる)によって、必要に応じて内部バッファが拡張される可能性があります。 ベンチマークの文脈では、bytes.NewBuffer を使用すると、たとえ読み込み専用の操作であっても、bytes.Buffer の内部実装が bytes.Reader よりも複雑であるため、わずかながらオーバーヘッドが発生する可能性があります。特に、io.Copy のような操作では、bytes.Bufferio.Reader インターフェースを満たすために、内部で追加のチェックや処理が行われることが考えられます。

  • bytes.NewReader(buf []byte): この関数は、与えられたバイトスライス buf を読み込み専用のデータソースとする bytes.Reader を作成します。bytes.Reader は内部バッファを拡張することなく、常に固定のバイトスライスから読み込みを行います。 ベンチマークの文脈では、bytes.NewReader は読み込み専用の操作に特化しているため、bytes.NewBuffer よりも効率的です。不要なメモリ割り当てやバッファの拡張ロジックがないため、より純粋な読み込み性能を測定できます。io.Copysrc として bytes.NewReader を使用する場合、bytes.Readerio.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つの変更が加えられています。

  1. b.ReportAllocs() の追加:

    func benchmarkDecode(b *testing.B, testfile, level, n int) {
    +	b.ReportAllocs()
    	b.StopTimer()
    	// ...
    }
    

    benchmarkDecode 関数の冒頭に b.ReportAllocs() が追加されました。これにより、このベンチマークを実行する際に、Goのテストフレームワークが実行時間だけでなく、ベンチマーク中に発生したメモリ割り当ての回数と合計バイト数も計測し、結果として報告するようになります。これは、compress/flate のデコード処理のメモリ効率を評価するための重要な指標となります。

  2. io.Copy のソースを bytes.NewBuffer から bytes.NewReader へ変更 (1回目):

    -		io.Copy(w, bytes.NewBuffer(buf0))
    +		io.Copy(w, bytes.NewReader(buf0))
    

    これは、圧縮前のデータ buf0flate.Writer (w) にコピーする部分の変更です。以前は bytes.NewBuffer(buf0) を使用していましたが、これを bytes.NewReader(buf0) に変更しました。 buf0ioutil.ReadFile で読み込まれた固定長のバイトスライスであり、読み込み専用のデータソースとして使用されます。このような場合、bytes.NewReader を使用する方が bytes.NewBuffer よりも効率的です。bytes.NewReader は内部でバッファの拡張を考慮する必要がなく、読み込みに特化しているため、ベンチマークのオーバーヘッドを削減し、より正確な圧縮処理の性能を測定できます。

  3. io.Copy のソースを bytes.NewBuffer から bytes.NewReader へ変更 (2回目):

    -		io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1)))
    +		io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
    

    これは、圧縮されたデータ buf1flate.Reader (NewReader(bytes.NewBuffer(buf1))) を通して ioutil.Discard (書き込まれたデータを破棄する io.Writer) にコピーする部分の変更です。ここでも、bytes.NewBuffer(buf1)bytes.NewReader(buf1) に変更されました。 buf1 もまた、圧縮された固定長のバイトスライスであり、デコード処理の入力として使用されます。ここでも、読み込み専用のデータソースとして bytes.NewReader を使用することで、デコード処理のベンチマークにおける入力準備のオーバーヘッドを最小限に抑え、より純粋なデコード性能を測定することが可能になります。

これらの変更は、compress/flate パッケージのベンチマークテストの精度と有用性を向上させることを目的としています。特に、メモリ割り当ての報告は、将来的な性能最適化のための重要な情報を提供します。

関連リンク

参考にした情報源リンク

このコミットは、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言語のベンチマークテストの精度と有用性を向上させる目的があります。

  1. bytes.NewBuffer から bytes.NewReader への変更: bytes.Buffer は可変長のバイトスライスを扱うための型で、主に書き込み操作(Write メソッドなど)によって内部バッファが拡張される可能性があります。一方、bytes.Reader は固定長のバイトスライスを読み込むための型で、内部バッファの拡張は発生しません。ベンチマークテストにおいて、入力データが固定であるにもかかわらず bytes.NewBuffer を使用すると、内部で不要なメモリ割り当てやコピーが発生し、ベンチマーク結果にノイズが混入する可能性があります。特に、io.Copy のような操作で bytes.Buffer をソースとして使用する場合、bytes.Bufferio.Reader インターフェースを満たしますが、その実装が bytes.Reader よりも効率的でない場合があります。この変更は、ベンチマークの対象となる compress/flate パッケージ自体の性能をより正確に測定するために、テストハーネス(テストコード)が引き起こすオーバーヘッドを最小限に抑えることを目的としています。

  2. ベンチマークでのメモリ割り当て報告 (b.ReportAllocs()): Goのベンチマークは通常、実行時間(ops/sec)を測定しますが、b.ReportAllocs() を呼び出すことで、ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数も報告されるようになります。これは、特にガベージコレクション(GC)の影響を受けやすいGo言語において、パフォーマンスチューニングの重要な指標となります。実行時間だけでなく、メモリ割り当ての状況を把握することで、より効率的なコードパスを見つけ出し、GCの負荷を軽減する改善を行うための手がかりを得ることができます。この変更は、compress/flate パッケージのデコード処理がどれだけメモリを効率的に使用しているかを評価するために追加されました。

要するに、このコミットは、compress/flate パッケージのベンチマークテストをより正確かつ包括的にすることで、将来的な性能改善のための基盤を強化することを目的としています。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念と標準ライブラリに関する知識が必要です。

  1. compress/flate パッケージ: compress/flate パッケージは、DEFLATEアルゴリズム(RFC 1951で定義)を実装したGo言語の標準ライブラリです。DEFLATEは、Zlibやgzipなどの圧縮形式の基盤となるデータ圧縮アルゴリズムです。このパッケージは、データの圧縮(エンコード)と解凍(デコード)機能を提供します。このコミットでは、主にデコード(解凍)のベンチマークテストが対象となっています。

  2. bytes パッケージ: bytes パッケージは、バイトスライスを操作するためのユーティリティ関数と型を提供します。

    • bytes.Buffer: 可変長のバイトバッファを実装する型です。io.Reader および io.Writer インターフェースを実装しており、バイトスライスへの書き込みやバイトスライスからの読み込みが可能です。内部的には必要に応じてバッファが拡張されます。
    • bytes.Reader: 固定長のバイトスライスから読み込むための型です。io.Reader, io.ReaderAt, io.Seeker, io.ByteReader, io.RuneReader インターフェースを実装しています。内部バッファは固定であり、拡張されることはありません。
  3. 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 に書き込むユーティリティ関数です。srcio.WriterTo インターフェースを実装している場合、その WriteTo メソッドが使用され、dstio.ReaderFrom インターフェースを実装している場合、その ReadFrom メソッドが使用されます。これにより、効率的なデータ転送が可能です。
  4. testing パッケージとベンチマーク: testing パッケージは、Go言語のテストとベンチマークをサポートするための機能を提供します。

    • *testing.B: ベンチマーク関数に渡される型で、ベンチマークの実行を制御し、結果を報告するためのメソッドを提供します。
    • b.ReportAllocs(): ベンチマーク実行中に発生したメモリ割り当ての回数と合計バイト数を報告するように設定します。このメソッドは、ベンチマーク関数の開始時に一度だけ呼び出す必要があります。
    • b.StopTimer() / b.StartTimer(): ベンチマークの計測時間を一時停止/再開します。セットアップやクリーンアップなど、ベンチマーク対象外の処理の時間を計測から除外するために使用されます。
    • b.SetBytes(n int64): 1回の操作で処理されるバイト数を設定します。これにより、ベンチマーク結果が「操作/秒」だけでなく「バイト/秒」としても報告されるようになります。
    • b.N: ベンチマーク関数が実行されるイテレーション回数です。testing パッケージが自動的に調整し、統計的に有意な結果が得られるようにします。
  5. runtime.GC(): runtime パッケージは、Goランタイムとの相互作用を可能にする関数を提供します。runtime.GC() は、ガベージコレクタを強制的に実行します。ベンチマークにおいて、GCの影響を均一にするためや、特定の処理の直後にメモリをクリーンアップするために使用されることがあります。

技術的詳細

このコミットの技術的な核心は、bytes.NewBufferbytes.NewReader の使い分け、およびベンチマークにおけるメモリ割り当ての重要性にあります。

bytes.NewBufferbytes.NewReader の違いとベンチマークへの影響

  • bytes.NewBuffer(buf []byte): この関数は、与えられたバイトスライス buf を初期内容とする bytes.Buffer を作成します。bytes.Buffer は内部に可変長のバイトスライスを持っており、書き込み操作(例: io.Copysrcbytes.Buffer の場合、bytes.BufferRead メソッドが呼ばれる)によって、必要に応じて内部バッファが拡張される可能性があります。 ベンチマークの文脈では、bytes.NewBuffer を使用すると、たとえ読み込み専用の操作であっても、bytes.Buffer の内部実装が bytes.Reader よりも複雑であるため、わずかながらオーバーヘッドが発生する可能性があります。特に、io.Copy のような操作では、bytes.Bufferio.Reader インターフェースを満たすために、内部で追加のチェックや処理が行われることが考えられます。

  • bytes.NewReader(buf []byte): この関数は、与えられたバイトスライス buf を読み込み専用のデータソースとする bytes.Reader を作成します。bytes.Reader は内部バッファを拡張することなく、常に固定のバイトスライスから読み込みを行います。 ベンチマークの文脈では、bytes.NewReader は読み込み専用の操作に特化しているため、bytes.NewBuffer よりも効率的です。不要なメモリ割り当てやバッファの拡張ロジックがないため、より純粋な読み込み性能を測定できます。io.Copysrc として bytes.NewReader を使用する場合、bytes.Readerio.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つの変更が加えられています。

  1. b.ReportAllocs() の追加:

    func benchmarkDecode(b *testing.B, testfile, level, n int) {
    +	b.ReportAllocs()
    	b.StopTimer()
    	// ...
    }
    

    benchmarkDecode 関数の冒頭に b.ReportAllocs() が追加されました。これにより、このベンチマークを実行する際に、Goのテストフレームワークが実行時間だけでなく、ベンチマーク中に発生したメモリ割り当ての回数と合計バイト数も計測し、結果として報告するようになります。これは、compress/flate のデコード処理のメモリ効率を評価するための重要な指標となります。

  2. io.Copy のソースを bytes.NewBuffer から bytes.NewReader へ変更 (1回目):

    -		io.Copy(w, bytes.NewBuffer(buf0))
    +		io.Copy(w, bytes.NewReader(buf0))
    

    これは、圧縮前のデータ buf0flate.Writer (w) にコピーする部分の変更です。以前は bytes.NewBuffer(buf0) を使用していましたが、これを bytes.NewReader(buf0) に変更しました。 buf0ioutil.ReadFile で読み込まれた固定長のバイトスライスであり、読み込み専用のデータソースとして使用されます。このような場合、bytes.NewReader を使用する方が bytes.NewBuffer よりも効率的です。bytes.NewReader は内部でバッファの拡張を考慮する必要がなく、読み込みに特化しているため、ベンチマークのオーバーヘッドを削減し、より正確な圧縮処理の性能を測定できます。

  3. io.Copy のソースを bytes.NewBuffer から bytes.NewReader へ変更 (2回目):

    -		io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1)))
    +		io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
    

    これは、圧縮されたデータ buf1flate.Reader (NewReader(bytes.NewBuffer(buf1))) を通して ioutil.Discard (書き込まれたデータを破棄する io.Writer) にコピーする部分の変更です。ここでも、bytes.NewBuffer(buf1)bytes.NewReader(buf1) に変更されました。 buf1 もまた、圧縮された固定長のバイトスライスであり、デコード処理の入力として使用されます。ここでも、読み込み専用のデータソースとして bytes.NewReader を使用することで、デコード処理のベンチマークにおける入力準備のオーバーヘッドを最小限に抑え、より純粋なデコード性能を測定することが可能になります。

これらの変更は、compress/flate パッケージのベンチマークテストの精度と有用性を向上させることを目的としています。特に、メモリ割り当ての報告は、将来的な性能最適化のための重要な情報を提供します。

関連リンク

参考にした情報源リンク