Browse code

Optimizations for StdWriter

Avoids allocations and copying by using a buffer pool for intermediate
writes.

```
benchmark old ns/op new ns/op delta
BenchmarkWrite-8 996 175 -82.43%

benchmark old MB/s new MB/s speedup
BenchmarkWrite-8 4414.48 25069.46 5.68x

benchmark old allocs new allocs delta
BenchmarkWrite-8 2 0 -100.00%

benchmark old bytes new bytes delta
BenchmarkWrite-8 4616 0 -100.00%
```

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2016/03/21 12:25:11
Showing 1 changed files
... ...
@@ -1,10 +1,12 @@
1 1
 package stdcopy
2 2
 
3 3
 import (
4
+	"bytes"
4 5
 	"encoding/binary"
5 6
 	"errors"
6 7
 	"fmt"
7 8
 	"io"
9
+	"sync"
8 10
 
9 11
 	"github.com/Sirupsen/logrus"
10 12
 )
... ...
@@ -28,6 +30,8 @@ const (
28 28
 	startingBufLen = 32*1024 + stdWriterPrefixLen + 1
29 29
 )
30 30
 
31
+var bufPool = &sync.Pool{New: func() interface{} { return bytes.NewBuffer(nil) }}
32
+
31 33
 // stdWriter is wrapper of io.Writer with extra customized info.
32 34
 type stdWriter struct {
33 35
 	io.Writer
... ...
@@ -35,28 +39,31 @@ type stdWriter struct {
35 35
 }
36 36
 
37 37
 // Write sends the buffer to the underneath writer.
38
-// It insert the prefix header before the buffer,
38
+// It inserts the prefix header before the buffer,
39 39
 // so stdcopy.StdCopy knows where to multiplex the output.
40 40
 // It makes stdWriter to implement io.Writer.
41
-func (w *stdWriter) Write(buf []byte) (n int, err error) {
41
+func (w *stdWriter) Write(p []byte) (n int, err error) {
42 42
 	if w == nil || w.Writer == nil {
43 43
 		return 0, errors.New("Writer not instantiated")
44 44
 	}
45
-	if buf == nil {
45
+	if p == nil {
46 46
 		return 0, nil
47 47
 	}
48 48
 
49 49
 	header := [stdWriterPrefixLen]byte{stdWriterFdIndex: w.prefix}
50
-	binary.BigEndian.PutUint32(header[stdWriterSizeIndex:], uint32(len(buf)))
51
-
52
-	line := append(header[:], buf...)
50
+	binary.BigEndian.PutUint32(header[stdWriterSizeIndex:], uint32(len(p)))
51
+	buf := bufPool.Get().(*bytes.Buffer)
52
+	buf.Write(header[:])
53
+	buf.Write(p)
53 54
 
54
-	n, err = w.Writer.Write(line)
55
+	n, err = w.Writer.Write(buf.Bytes())
55 56
 	n -= stdWriterPrefixLen
56
-
57 57
 	if n < 0 {
58 58
 		n = 0
59 59
 	}
60
+
61
+	buf.Reset()
62
+	bufPool.Put(buf)
60 63
 	return
61 64
 }
62 65