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>
| ... | ... |
@@ -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 |
|