From 6a1c1c66145d2a196efdc81b70b734ec5f42d09c Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Sun, 8 Oct 2023 20:53:36 +0200 Subject: [PATCH 01/11] made f.step an enum instead of func pointer according to my local benchmarks, it doesn't affect throughtput anyhow, but leaves constant 1 allocation/op in decompressor benchmarks --- flate/_gen/gen_inflate.go | 4 +-- flate/inflate.go | 62 ++++++++++++++++++++++++++++++++++----- flate/inflate_gen.go | 20 ++++++------- 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/flate/_gen/gen_inflate.go b/flate/_gen/gen_inflate.go index 64ff1aad4c..1a35f90cae 100644 --- a/flate/_gen/gen_inflate.go +++ b/flate/_gen/gen_inflate.go @@ -109,7 +109,7 @@ readLiteral: dict.writeByte(byte(v)) if dict.availWrite() == 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).$FUNCNAME$ + f.step = $FUNCNAME$ f.stepState = stateInit f.b, f.nb = fb, fnb return @@ -275,7 +275,7 @@ copyHistory: if dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).$FUNCNAME$ // We need to continue this work + f.step = $FUNCNAME$ // We need to continue this work f.stepState = stateDict f.b, f.nb = fb, fnb return diff --git a/flate/inflate.go b/flate/inflate.go index 414c0bea9f..0547fa66ba 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -285,6 +285,18 @@ type Reader interface { io.ByteReader } +type step uint8 + +const ( + copyData step = iota + 1 + nextBlock + huffmanBytesBuffer + huffmanBytesReader + huffmanBufioReader + huffmanStringsReader + huffmanGenericReader +) + // Decompress state. type decompressor struct { // Input source. @@ -303,7 +315,7 @@ type decompressor struct { // Next step in the decompression, // and decompression state. - step func(*decompressor) + step step stepState int err error toRead []byte @@ -379,7 +391,24 @@ func (f *decompressor) Read(b []byte) (int, error) { if f.err != nil { return 0, f.err } - f.step(f) + + switch f.step { + case copyData: + f.copyData() + case nextBlock: + f.nextBlock() + case huffmanBytesBuffer: + f.huffmanBytesBuffer() + case huffmanBytesReader: + f.huffmanBytesReader() + case huffmanBufioReader: + f.huffmanBufioReader() + case huffmanStringsReader: + f.huffmanStringsReader() + case huffmanGenericReader: + f.huffmanGenericReader() + } + if f.err != nil && len(f.toRead) == 0 { f.toRead = f.dict.readFlush() // Flush what's left in case of error } @@ -410,7 +439,22 @@ func (f *decompressor) WriteTo(w io.Writer) (int64, error) { return total, f.err } if f.err == nil { - f.step(f) + switch f.step { + case copyData: + f.copyData() + case nextBlock: + f.nextBlock() + case huffmanBytesBuffer: + f.huffmanBytesBuffer() + case huffmanBytesReader: + f.huffmanBytesReader() + case huffmanBufioReader: + f.huffmanBufioReader() + case huffmanStringsReader: + f.huffmanStringsReader() + case huffmanGenericReader: + f.huffmanGenericReader() + } } if len(f.toRead) == 0 && f.err != nil && !flushed { f.toRead = f.dict.readFlush() // Flush what's left in case of error @@ -631,7 +675,8 @@ func (f *decompressor) copyData() { if f.dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = f.dict.readFlush() - f.step = (*decompressor).copyData + f.step = copyData + //f.step = (*decompressor).copyData return } f.finishBlock() @@ -644,7 +689,8 @@ func (f *decompressor) finishBlock() { } f.err = io.EOF } - f.step = (*decompressor).nextBlock + f.step = nextBlock + //f.step = (*decompressor).nextBlock } // noEOF returns err, unless err == io.EOF, in which case it returns io.ErrUnexpectedEOF. @@ -747,7 +793,7 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error { h1: f.h1, h2: f.h2, dict: f.dict, - step: (*decompressor).nextBlock, + step: nextBlock, } f.dict.init(maxMatchOffset, dict) return nil @@ -768,7 +814,7 @@ func NewReader(r io.Reader) io.ReadCloser { f.r = makeReader(r) f.bits = new([maxNumLit + maxNumDist]int) f.codebits = new([numCodes]int) - f.step = (*decompressor).nextBlock + f.step = nextBlock f.dict.init(maxMatchOffset, nil) return &f } @@ -787,7 +833,7 @@ func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser { f.r = makeReader(r) f.bits = new([maxNumLit + maxNumDist]int) f.codebits = new([numCodes]int) - f.step = (*decompressor).nextBlock + f.step = nextBlock f.dict.init(maxMatchOffset, dict) return &f } diff --git a/flate/inflate_gen.go b/flate/inflate_gen.go index 61342b6b88..18f2864992 100644 --- a/flate/inflate_gen.go +++ b/flate/inflate_gen.go @@ -85,7 +85,7 @@ readLiteral: dict.writeByte(byte(v)) if dict.availWrite() == 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanBytesBuffer + f.step = huffmanBytesBuffer f.stepState = stateInit f.b, f.nb = fb, fnb return @@ -251,7 +251,7 @@ copyHistory: if dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanBytesBuffer // We need to continue this work + f.step = huffmanBytesBuffer // We need to continue this work f.stepState = stateDict f.b, f.nb = fb, fnb return @@ -336,7 +336,7 @@ readLiteral: dict.writeByte(byte(v)) if dict.availWrite() == 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanBytesReader + f.step = huffmanBytesReader f.stepState = stateInit f.b, f.nb = fb, fnb return @@ -502,7 +502,7 @@ copyHistory: if dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanBytesReader // We need to continue this work + f.step = huffmanBytesReader // We need to continue this work f.stepState = stateDict f.b, f.nb = fb, fnb return @@ -587,7 +587,7 @@ readLiteral: dict.writeByte(byte(v)) if dict.availWrite() == 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanBufioReader + f.step = huffmanBufioReader f.stepState = stateInit f.b, f.nb = fb, fnb return @@ -753,7 +753,7 @@ copyHistory: if dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanBufioReader // We need to continue this work + f.step = huffmanBufioReader // We need to continue this work f.stepState = stateDict f.b, f.nb = fb, fnb return @@ -838,7 +838,7 @@ readLiteral: dict.writeByte(byte(v)) if dict.availWrite() == 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanStringsReader + f.step = huffmanStringsReader f.stepState = stateInit f.b, f.nb = fb, fnb return @@ -1004,7 +1004,7 @@ copyHistory: if dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanStringsReader // We need to continue this work + f.step = huffmanStringsReader // We need to continue this work f.stepState = stateDict f.b, f.nb = fb, fnb return @@ -1089,7 +1089,7 @@ readLiteral: dict.writeByte(byte(v)) if dict.availWrite() == 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanGenericReader + f.step = huffmanGenericReader f.stepState = stateInit f.b, f.nb = fb, fnb return @@ -1255,7 +1255,7 @@ copyHistory: if dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = dict.readFlush() - f.step = (*decompressor).huffmanGenericReader // We need to continue this work + f.step = huffmanGenericReader // We need to continue this work f.stepState = stateDict f.b, f.nb = fb, fnb return From 1203209a7e1bbdfa79141ec5661b57e2ccdbe4dd Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Sun, 8 Oct 2023 21:11:42 +0200 Subject: [PATCH 02/11] removed useless array-to-slice conversion this conversion doesn't do anything, and removing it doesn't fail any of the tests --- flate/inflate.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/flate/inflate.go b/flate/inflate.go index 0547fa66ba..37e8da78a5 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -175,9 +175,8 @@ func (h *huffmanDecoder) init(lengths []int) bool { } h.maxRead = min - chunks := h.chunks[:] - for i := range chunks { - chunks[i] = 0 + for i := range h.chunks { + h.chunks[i] = 0 } if max > huffmanChunkBits { From a4773a95c30044de0082747b2319dfcba3f7b7e1 Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Sun, 8 Oct 2023 21:13:52 +0200 Subject: [PATCH 03/11] made benchmarks more accurate by removing io.Copy call as io.Copy is just an alias for io.CopyBuffer, but passing nil instead of the actual buffer, it is being allocated internally. So better to pass it manually --- flate/reader_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flate/reader_test.go b/flate/reader_test.go index 37e9b912fe..7b65d7558a 100644 --- a/flate/reader_test.go +++ b/flate/reader_test.go @@ -64,13 +64,15 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) { w.Close() buf1 := compressed.Bytes() buf0, compressed, w = nil, nil, nil + const ioCopyBuffSize = 32 * 1024 // taken from io.copyBuffer, in case passed buf==nil + ioCopyBuff := make([]byte, ioCopyBuffSize) runtime.GC() b.StartTimer() r := NewReader(bytes.NewReader(buf1)) res := r.(Resetter) for i := 0; i < b.N; i++ { res.Reset(bytes.NewReader(buf1), nil) - io.Copy(io.Discard, r) + io.CopyBuffer(io.Discard, r, ioCopyBuff) } } From c127997432d9a7798d12c303b60dbd1eb0cafef4 Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 01:49:28 +0200 Subject: [PATCH 04/11] removed useless operation of nulling the length of the slice this operation does nothing, so remoed it --- flate/inflate.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flate/inflate.go b/flate/inflate.go index 37e8da78a5..515c504953 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -201,8 +201,7 @@ func (h *huffmanDecoder) init(lengths []int) bool { if cap(h.links[off]) < numLinks { h.links[off] = make([]uint16, numLinks) } else { - links := h.links[off][:0] - h.links[off] = links[:numLinks] + h.links[off] = h.links[off][:numLinks] } } } else { From 98e21c731ffbf75da76b2d9bcc15fa316540a358 Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 01:51:02 +0200 Subject: [PATCH 05/11] moved b.StartTimer() to the bottom previous variant wasn't actually adding a big misaccuracy, but better to place it anyway just before a benchmarking code --- flate/reader_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/flate/reader_test.go b/flate/reader_test.go index 7b65d7558a..d9db6cdb05 100644 --- a/flate/reader_test.go +++ b/flate/reader_test.go @@ -66,13 +66,14 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) { buf0, compressed, w = nil, nil, nil const ioCopyBuffSize = 32 * 1024 // taken from io.copyBuffer, in case passed buf==nil ioCopyBuff := make([]byte, ioCopyBuffSize) - runtime.GC() - b.StartTimer() r := NewReader(bytes.NewReader(buf1)) res := r.(Resetter) + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { - res.Reset(bytes.NewReader(buf1), nil) - io.CopyBuffer(io.Discard, r, ioCopyBuff) + _ = res.Reset(bytes.NewReader(buf1), nil) + _, _ = io.CopyBuffer(io.Discard, r, ioCopyBuff) } } From 4c8d7a2addfba65a169ce4c12223a6b98f85eb43 Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 01:52:30 +0200 Subject: [PATCH 06/11] replaced indirect decoder call with direct instead of returning func ptr, calling the method directly. This also doesn't bring a lot of performance gains, but on microbenchmarks may be visible --- flate/_gen/gen_inflate.go | 6 +++--- flate/inflate.go | 7 ++++--- flate/inflate_gen.go | 14 +++++++------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/flate/_gen/gen_inflate.go b/flate/_gen/gen_inflate.go index 1a35f90cae..33f1400576 100644 --- a/flate/_gen/gen_inflate.go +++ b/flate/_gen/gen_inflate.go @@ -291,13 +291,13 @@ copyHistory: s = strings.Replace(s, "$TYPE$", t, -1) f.WriteString(s) } - f.WriteString("func (f *decompressor) huffmanBlockDecoder() func() {\n") + f.WriteString("func (f *decompressor) huffmanBlockDecoder() {\n") f.WriteString("\tswitch f.r.(type) {\n") for i, t := range types { f.WriteString("\t\tcase " + t + ":\n") - f.WriteString("\t\t\treturn f.huffman" + names[i] + "\n") + f.WriteString("\t\t\tf.huffman" + names[i] + "()\n") } f.WriteString("\t\tdefault:\n") - f.WriteString("\t\t\treturn f.huffmanGenericReader\n") + f.WriteString("\t\t\tf.huffmanGenericReader()\n") f.WriteString("\t}\n}\n") } diff --git a/flate/inflate.go b/flate/inflate.go index 515c504953..1029b2b5eb 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -120,8 +120,9 @@ func (h *huffmanDecoder) init(lengths []int) bool { const sanity = false if h.chunks == nil { - h.chunks = &[huffmanNumChunks]uint16{} + h.chunks = new([huffmanNumChunks]uint16) } + if h.maxRead != 0 { *h = huffmanDecoder{chunks: h.chunks, links: h.links} } @@ -352,7 +353,7 @@ func (f *decompressor) nextBlock() { // compressed, fixed Huffman tables f.hl = &fixedHuffmanDecoder f.hd = nil - f.huffmanBlockDecoder()() + f.huffmanBlockDecoder() if debugDecode { fmt.Println("predefinied huffman block") } @@ -363,7 +364,7 @@ func (f *decompressor) nextBlock() { } f.hl = &f.h1 f.hd = &f.h2 - f.huffmanBlockDecoder()() + f.huffmanBlockDecoder() if debugDecode { fmt.Println("dynamic huffman block") } diff --git a/flate/inflate_gen.go b/flate/inflate_gen.go index 18f2864992..2b2f993f75 100644 --- a/flate/inflate_gen.go +++ b/flate/inflate_gen.go @@ -1265,19 +1265,19 @@ copyHistory: // Not reached } -func (f *decompressor) huffmanBlockDecoder() func() { +func (f *decompressor) huffmanBlockDecoder() { switch f.r.(type) { case *bytes.Buffer: - return f.huffmanBytesBuffer + f.huffmanBytesBuffer() case *bytes.Reader: - return f.huffmanBytesReader + f.huffmanBytesReader() case *bufio.Reader: - return f.huffmanBufioReader + f.huffmanBufioReader() case *strings.Reader: - return f.huffmanStringsReader + f.huffmanStringsReader() case Reader: - return f.huffmanGenericReader + f.huffmanGenericReader() default: - return f.huffmanGenericReader + f.huffmanGenericReader() } } From e40efbf0f35891a240271ef39e5e23f5a6c2406e Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 02:02:41 +0200 Subject: [PATCH 07/11] removed somehow commented code --- flate/inflate.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/flate/inflate.go b/flate/inflate.go index 1029b2b5eb..59c13eb41d 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -675,7 +675,6 @@ func (f *decompressor) copyData() { if f.dict.availWrite() == 0 || f.copyLen > 0 { f.toRead = f.dict.readFlush() f.step = copyData - //f.step = (*decompressor).copyData return } f.finishBlock() @@ -689,7 +688,6 @@ func (f *decompressor) finishBlock() { f.err = io.EOF } f.step = nextBlock - //f.step = (*decompressor).nextBlock } // noEOF returns err, unless err == io.EOF, in which case it returns io.ErrUnexpectedEOF. From d517f8e090cc97f5cf03b246f0c7706702068ca9 Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 13:20:59 +0200 Subject: [PATCH 08/11] moved execution of next step into the dedicated method this improves readability of the code. Also added a debug print in case next step enumeric is unrecognized. However, everything will silently fail even without this print --- flate/inflate.go | 57 +++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/flate/inflate.go b/flate/inflate.go index 59c13eb41d..5f30eb533f 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -391,22 +391,7 @@ func (f *decompressor) Read(b []byte) (int, error) { return 0, f.err } - switch f.step { - case copyData: - f.copyData() - case nextBlock: - f.nextBlock() - case huffmanBytesBuffer: - f.huffmanBytesBuffer() - case huffmanBytesReader: - f.huffmanBytesReader() - case huffmanBufioReader: - f.huffmanBufioReader() - case huffmanStringsReader: - f.huffmanStringsReader() - case huffmanGenericReader: - f.huffmanGenericReader() - } + f.doStep() if f.err != nil && len(f.toRead) == 0 { f.toRead = f.dict.readFlush() // Flush what's left in case of error @@ -438,22 +423,7 @@ func (f *decompressor) WriteTo(w io.Writer) (int64, error) { return total, f.err } if f.err == nil { - switch f.step { - case copyData: - f.copyData() - case nextBlock: - f.nextBlock() - case huffmanBytesBuffer: - f.huffmanBytesBuffer() - case huffmanBytesReader: - f.huffmanBytesReader() - case huffmanBufioReader: - f.huffmanBufioReader() - case huffmanStringsReader: - f.huffmanStringsReader() - case huffmanGenericReader: - f.huffmanGenericReader() - } + f.doStep() } if len(f.toRead) == 0 && f.err != nil && !flushed { f.toRead = f.dict.readFlush() // Flush what's left in case of error @@ -690,6 +660,29 @@ func (f *decompressor) finishBlock() { f.step = nextBlock } +func (f *decompressor) doStep() { + switch f.step { + case copyData: + f.copyData() + case nextBlock: + f.nextBlock() + case huffmanBytesBuffer: + f.huffmanBytesBuffer() + case huffmanBytesReader: + f.huffmanBytesReader() + case huffmanBufioReader: + f.huffmanBufioReader() + case huffmanStringsReader: + f.huffmanStringsReader() + case huffmanGenericReader: + f.huffmanGenericReader() + default: + if debugDecode { + fmt.Println("BUG: unexpected step state") + } + } +} + // noEOF returns err, unless err == io.EOF, in which case it returns io.ErrUnexpectedEOF. func noEOF(e error) error { if e == io.EOF { From fbb9795199fef7bff4d1882390eb0829e91e4eb6 Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 13:21:31 +0200 Subject: [PATCH 09/11] copying zeros into chunks instead of iterating over it and setting manually --- flate/inflate.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/flate/inflate.go b/flate/inflate.go index 5f30eb533f..a2b228a441 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -43,6 +43,9 @@ var bitMask32 = [32]uint32{ 0x1ffFFFF, 0x3ffFFFF, 0x7ffFFFF, 0xfffFFFF, 0x1fffFFFF, 0x3fffFFFF, 0x7fffFFFF, } // up to 32 bits +// zeroChunks is used to nullify decompressor.chunks array +var zeroChunks = make([]uint16, huffmanNumChunks) + // Initialize the fixedHuffmanDecoder only once upon first use. var fixedOnce sync.Once var fixedHuffmanDecoder huffmanDecoder @@ -176,9 +179,10 @@ func (h *huffmanDecoder) init(lengths []int) bool { } h.maxRead = min - for i := range h.chunks { - h.chunks[i] = 0 - } + + // instead of iterating over the whole array, just copy already null-filled + // slice in it. + copy(h.chunks[:], zeroChunks) if max > huffmanChunkBits { numLinks := 1 << (uint(max) - huffmanChunkBits) @@ -276,7 +280,7 @@ func (h *huffmanDecoder) init(lengths []int) bool { return true } -// The actual read interface needed by NewReader. +// Reader is the actual read interface needed by NewReader. // If the passed in io.Reader does not also have ReadByte, // the NewReader will introduce its own buffering. type Reader interface { From 863cd97e368704ec3532f2beab078581c22d1bc8 Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 14:02:17 +0200 Subject: [PATCH 10/11] added panic in case of unknown step state, brought old way to zero chunks array back --- flate/inflate.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/flate/inflate.go b/flate/inflate.go index a2b228a441..2f410d64f5 100644 --- a/flate/inflate.go +++ b/flate/inflate.go @@ -43,9 +43,6 @@ var bitMask32 = [32]uint32{ 0x1ffFFFF, 0x3ffFFFF, 0x7ffFFFF, 0xfffFFFF, 0x1fffFFFF, 0x3fffFFFF, 0x7fffFFFF, } // up to 32 bits -// zeroChunks is used to nullify decompressor.chunks array -var zeroChunks = make([]uint16, huffmanNumChunks) - // Initialize the fixedHuffmanDecoder only once upon first use. var fixedOnce sync.Once var fixedHuffmanDecoder huffmanDecoder @@ -180,9 +177,10 @@ func (h *huffmanDecoder) init(lengths []int) bool { h.maxRead = min - // instead of iterating over the whole array, just copy already null-filled - // slice in it. - copy(h.chunks[:], zeroChunks) + chunks := h.chunks[:] + for i := range chunks { + chunks[i] = 0 + } if max > huffmanChunkBits { numLinks := 1 << (uint(max) - huffmanChunkBits) @@ -403,7 +401,7 @@ func (f *decompressor) Read(b []byte) (int, error) { } } -// Support the io.WriteTo interface for io.Copy and friends. +// WriteTo implements the io.WriteTo interface for io.Copy and friends. func (f *decompressor) WriteTo(w io.Writer) (int64, error) { total := int64(0) flushed := false @@ -681,9 +679,7 @@ func (f *decompressor) doStep() { case huffmanGenericReader: f.huffmanGenericReader() default: - if debugDecode { - fmt.Println("BUG: unexpected step state") - } + panic("BUG: unexpected step state") } } From 1248009e4a17491e1e8fa5572c8190b5089e757a Mon Sep 17 00:00:00 2001 From: fakefloordiv Date: Mon, 9 Oct 2023 23:25:45 +0200 Subject: [PATCH 11/11] rollback to io.Copy as flate reader implements WriterTo interface, there's completely no difference what to use --- flate/reader_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flate/reader_test.go b/flate/reader_test.go index d9db6cdb05..6eedfb9b77 100644 --- a/flate/reader_test.go +++ b/flate/reader_test.go @@ -64,8 +64,6 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) { w.Close() buf1 := compressed.Bytes() buf0, compressed, w = nil, nil, nil - const ioCopyBuffSize = 32 * 1024 // taken from io.copyBuffer, in case passed buf==nil - ioCopyBuff := make([]byte, ioCopyBuffSize) r := NewReader(bytes.NewReader(buf1)) res := r.(Resetter) runtime.GC() @@ -73,7 +71,7 @@ func benchmarkDecode(b *testing.B, testfile, level, n int) { for i := 0; i < b.N; i++ { _ = res.Reset(bytes.NewReader(buf1), nil) - _, _ = io.CopyBuffer(io.Discard, r, ioCopyBuff) + _, _ = io.Copy(io.Discard, r) } }