From 373e25552c927b3bea32511aac6ce150aac6b984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Tue, 7 Sep 2021 16:49:03 +0200 Subject: [PATCH] avoid double alloc in NewCidV1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- cid.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/cid.go b/cid.go index dc80750..2f3bbf6 100644 --- a/cid.go +++ b/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 (