diff options
author | Rob Pike <r@golang.org> | 2009-12-06 12:03:52 -0800 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2009-12-06 12:03:52 -0800 |
commit | 25ce0349b3305d038c757b2a49c91c7ca05848c9 (patch) | |
tree | 9ca97cb7ed859f7cc96604a32683841585024c79 /src/pkg/bytes/buffer.go | |
parent | 956d8c7dec13e1a90061f81c321d6ccd588a3a6e (diff) | |
download | golang-25ce0349b3305d038c757b2a49c91c7ca05848c9.tar.gz |
Make printing faster by avoiding mallocs and some other advances.
Roughly 33% faster for simple cases, probably more for complex ones.
Before:
mallocs per Sprintf(""): 4
mallocs per Sprintf("xxx"): 6
mallocs per Sprintf("%x"): 10
mallocs per Sprintf("%x %x"): 12
Now:
mallocs per Sprintf(""): 2
mallocs per Sprintf("xxx"): 3
mallocs per Sprintf("%x"): 5
mallocs per Sprintf("%x %x"): 7
Speed improves because of avoiding mallocs and also by sharing a bytes.Buffer
between print.go and format.go rather than copying the data back after each
printed item.
Before:
fmt_test.BenchmarkSprintfEmpty 1000000 1346 ns/op
fmt_test.BenchmarkSprintfString 500000 3461 ns/op
fmt_test.BenchmarkSprintfInt 500000 3671 ns/op
Now:
fmt_test.BenchmarkSprintfEmpty 2000000 995 ns/op
fmt_test.BenchmarkSprintfString 1000000 2745 ns/op
fmt_test.BenchmarkSprintfInt 1000000 2391 ns/op
fmt_test.BenchmarkSprintfIntInt 500000 3751 ns/op
I believe there is more to get but this is a good milestone.
R=rsc
CC=golang-dev, hong
http://codereview.appspot.com/166076
Diffstat (limited to 'src/pkg/bytes/buffer.go')
-rw-r--r-- | src/pkg/bytes/buffer.go | 74 |
1 files changed, 37 insertions, 37 deletions
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go index 09202506f..61780947f 100644 --- a/src/pkg/bytes/buffer.go +++ b/src/pkg/bytes/buffer.go @@ -32,9 +32,10 @@ func copyBytes(dst []byte, doff int, src []byte) { // 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)] - oneByte [1]byte; // avoid allocation of slice on each WriteByte + buf []byte; // contents are the bytes buf[off : len(buf)] + off int; // read at &buf[off], write at &buf[len(buf)] + oneByte [1]byte; // avoid allocation of slice on each WriteByte + bootstrap [64]byte; // memory to hold first slice; helps small buffers (Printf) avoid allocation. } // Bytes returns the contents of the unread portion of the buffer; @@ -69,29 +70,51 @@ func (b *Buffer) Truncate(n int) { // b.Reset() is the same as b.Truncate(0). func (b *Buffer) Reset() { b.Truncate(0) } +// Resize buffer to guarantee enough space for n more bytes. +// After this call, the state of b.buf is inconsistent. +// It must be fixed up as is done in Write and WriteString. +func (b *Buffer) resize(n int) { + var buf []byte; + if b.buf == nil && n <= len(b.bootstrap) { + buf = &b.bootstrap + } else { + buf = b.buf; + if len(b.buf)+n > cap(b.buf) { + // not enough space anywhere + buf = make([]byte, 2*cap(b.buf)+n) + } + copy(buf, b.buf[b.off:]); + } + b.buf = buf; + b.off = 0; +} + // Write appends the contents of p to the buffer. The return // value n is the length of p; err is always nil. func (b *Buffer) Write(p []byte) (n int, err os.Error) { m := b.Len(); n = len(p); - if len(b.buf)+n > cap(b.buf) { - // not enough space at end - buf := b.buf; - if m+n > cap(b.buf) { - // not enough space anywhere - buf = make([]byte, 2*cap(b.buf)+n) - } - copyBytes(buf, 0, b.buf[b.off:b.off+m]); - b.buf = buf; - b.off = 0; + b.resize(n) } - b.buf = b.buf[0 : b.off+m+n]; copyBytes(b.buf, b.off+m, p); return n, nil; } +// WriteString appends the contents of s to the buffer. The return +// value n is the length of s; err is always nil. +func (b *Buffer) WriteString(s string) (n int, err os.Error) { + m := b.Len(); + n = len(s); + if len(b.buf)+n > cap(b.buf) { + b.resize(n) + } + b.buf = b.buf[0 : b.off+m+n]; + copyString(b.buf, b.off+m, s); + return n, nil; +} + // MinRead is the minimum slice size passed to a Read call by // Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond // what is required to hold the contents of r, ReadFrom will not grow the @@ -146,29 +169,6 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) { return; } -// WriteString appends the contents of s to the buffer. The return -// value n is the length of s; err is always nil. -func (b *Buffer) WriteString(s string) (n int, err os.Error) { - m := b.Len(); - n = len(s); - - if len(b.buf)+n > cap(b.buf) { - // not enough space at end - buf := b.buf; - if m+n > cap(b.buf) { - // not enough space anywhere - buf = make([]byte, 2*cap(b.buf)+n) - } - copyBytes(buf, 0, b.buf[b.off:b.off+m]); - b.buf = buf; - b.off = 0; - } - - b.buf = b.buf[0 : b.off+m+n]; - copyString(b.buf, b.off+m, s); - return n, nil; -} - // WriteByte appends the byte c to the buffer. // The returned error is always nil, but is included // to match bufio.Writer's WriteByte. |