]> Cypherpunks repositories - gostls13.git/commitdiff
bytes: improve WriteRune performance
authorMartin Möhrmann <martisch@uos.de>
Wed, 7 Sep 2016 06:59:00 +0000 (08:59 +0200)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 8 Sep 2016 17:15:28 +0000 (17:15 +0000)
Remove the runeBytes buffer and write the utf8 encoding directly
to the internal buf byte slice.

name         old time/op   new time/op   delta
WriteRune-4   80.5µs ± 2%   57.1µs ± 2%  -29.06%  (p=0.000 n=20+20)

name         old speed     new speed     delta
WriteRune-4  153MB/s ± 2%  215MB/s ± 2%  +40.96%  (p=0.000 n=20+20)

Change-Id: Ic15f6e2d6e56a3d15c74f56159e2eae020ba73ba
Reviewed-on: https://go-review.googlesource.com/28816
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/bytes/buffer.go
src/bytes/buffer_test.go

index 9154a1b954597486dafc5192f23cd271b8ed9c57..fa4a51c17fcff7b878fe4acebe46381314b7307f 100644 (file)
@@ -15,11 +15,10 @@ import (
 // A Buffer is a variable-sized buffer of bytes with Read and Write methods.
 // The zero value for Buffer is an empty buffer ready to use.
 type Buffer struct {
-       buf       []byte            // contents are the bytes buf[off : len(buf)]
-       off       int               // read at &buf[off], write at &buf[len(buf)]
-       runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each call to WriteRune
-       bootstrap [64]byte          // memory to hold first slice; helps small buffers avoid allocation.
-       lastRead  readOp            // last read operation, so that Unread* can work correctly.
+       buf       []byte   // contents are the bytes buf[off : len(buf)]
+       off       int      // read at &buf[off], write at &buf[len(buf)]
+       bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
+       lastRead  readOp   // last read operation, so that Unread* can work correctly.
 }
 
 // The readOp constants describe the last action performed on
@@ -246,8 +245,10 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) {
                b.WriteByte(byte(r))
                return 1, nil
        }
-       n = utf8.EncodeRune(b.runeBytes[0:], r)
-       b.Write(b.runeBytes[0:n])
+       b.lastRead = opInvalid
+       m := b.grow(utf8.UTFMax)
+       n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r)
+       b.buf = b.buf[:m+n]
        return n, nil
 }
 
index 7de17ae47e28ff00f00dd295637a9917779e9e32..b1b85f979af6502c6d546a0e52a6262c6ec871a1 100644 (file)
@@ -514,6 +514,19 @@ func TestBufferGrowth(t *testing.T) {
        }
 }
 
+func BenchmarkWriteRune(b *testing.B) {
+       const n = 4 << 10
+       const r = '☺'
+       b.SetBytes(int64(n * utf8.RuneLen(r)))
+       buf := NewBuffer(make([]byte, n*utf8.UTFMax))
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               for i := 0; i < n; i++ {
+                       buf.WriteRune(r)
+               }
+       }
+}
+
 // From Issue 5154.
 func BenchmarkBufferNotEmptyWriteRead(b *testing.B) {
        buf := make([]byte, 1024)