avoid double alloc in NewCidV1
We allocate once via "make([]byte, len)",
and again when that buffer is converted to a string.
Thankfully, since Go 1.10 we have strings.Builder,
designed specifically for this use case.
In a downstream benchmark in go-car,
which needs to reconstruct many CID values,
we see small but nice gains:
name old time/op new time/op delta
ReadBlocks-16 1.09ms ± 4% 1.06ms ± 5% -3.33% (p=0.007 n=11+11)
name old speed new speed delta
ReadBlocks-16 478MB/s ± 4% 494MB/s ± 5% +3.46% (p=0.007 n=11+11)
name old alloc/op new alloc/op delta
ReadBlocks-16 1.30MB ± 0% 1.25MB ± 0% -3.86% (p=0.000 n=12+12)
name old allocs/op new allocs/op delta
ReadBlocks-16 9.50k ± 0% 8.45k ± 0% -11.05% (p=0.000 n=12+12)
This commit is contained in:
21
cid.go
21
cid.go
@@ -22,6 +22,7 @@ package cid
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -173,16 +174,24 @@ func NewCidV0(mhash mh.Multihash) Cid {
|
||||
// Panics if the multihash is invalid.
|
||||
func NewCidV1(codecType uint64, mhash mh.Multihash) Cid {
|
||||
hashlen := len(mhash)
|
||||
// two 8 bytes (max) numbers plus hash
|
||||
buf := make([]byte, 1+varint.UvarintSize(codecType)+hashlen)
|
||||
n := varint.PutUvarint(buf, 1)
|
||||
n += varint.PutUvarint(buf[n:], codecType)
|
||||
cn := copy(buf[n:], mhash)
|
||||
|
||||
// Two 8 bytes (max) numbers plus hash.
|
||||
// We use strings.Builder to only allocate once.
|
||||
var b strings.Builder
|
||||
b.Grow(1 + varint.UvarintSize(codecType) + hashlen)
|
||||
|
||||
b.WriteByte(1)
|
||||
|
||||
var buf [binary.MaxVarintLen64]byte
|
||||
n := varint.PutUvarint(buf[:], codecType)
|
||||
b.Write(buf[:n])
|
||||
|
||||
cn, _ := b.Write(mhash)
|
||||
if cn != hashlen {
|
||||
panic("copy hash length is inconsistent")
|
||||
}
|
||||
|
||||
return Cid{string(buf[:n+hashlen])}
|
||||
return Cid{b.String()}
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
Reference in New Issue
Block a user