triedb/pathdb: use binary.append to eliminate the tmp scratch slice (#32250)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

`binary.AppendUvarint` offers better performance than using append
directly, because it avoids unnecessary memory allocation and copying.

In our case, it can increase the performance by +35.8% for the
`blockWriter.append` function:

```
benchmark                        old ns/op     new ns/op     delta
BenchmarkBlockWriterAppend-8     5.97          3.83          -35.80%
```

---------

Signed-off-by: jsvisa <delweng@gmail.com>
Co-authored-by: Gary Rong <garyrong0905@gmail.com>
This commit is contained in:
Delweng 2025-07-22 20:03:22 +08:00 committed by GitHub
parent 83aa643621
commit 264c06a72c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 27 additions and 21 deletions

View file

@ -221,17 +221,14 @@ func (br *blockReader) readGreaterThan(id uint64) (uint64, error) {
type blockWriter struct { type blockWriter struct {
desc *indexBlockDesc // Descriptor of the block desc *indexBlockDesc // Descriptor of the block
restarts []uint16 // Offsets into the data slice, marking the start of each section restarts []uint16 // Offsets into the data slice, marking the start of each section
scratch []byte // Buffer used for encoding full integers or value differences
data []byte // Aggregated encoded data slice data []byte // Aggregated encoded data slice
} }
func newBlockWriter(blob []byte, desc *indexBlockDesc) (*blockWriter, error) { func newBlockWriter(blob []byte, desc *indexBlockDesc) (*blockWriter, error) {
scratch := make([]byte, binary.MaxVarintLen64)
if len(blob) == 0 { if len(blob) == 0 {
return &blockWriter{ return &blockWriter{
desc: desc, desc: desc,
scratch: scratch, data: make([]byte, 0, 1024),
data: make([]byte, 0, 1024),
}, nil }, nil
} }
restarts, data, err := parseIndexBlock(blob) restarts, data, err := parseIndexBlock(blob)
@ -241,7 +238,6 @@ func newBlockWriter(blob []byte, desc *indexBlockDesc) (*blockWriter, error) {
return &blockWriter{ return &blockWriter{
desc: desc, desc: desc,
restarts: restarts, restarts: restarts,
scratch: scratch,
data: data, // safe to own the slice data: data, // safe to own the slice
}, nil }, nil
} }
@ -268,22 +264,14 @@ func (b *blockWriter) append(id uint64) error {
// //
// The first element in a restart range is encoded using its // The first element in a restart range is encoded using its
// full value. // full value.
n := binary.PutUvarint(b.scratch[0:], id) b.data = binary.AppendUvarint(b.data, id)
b.data = append(b.data, b.scratch[:n]...)
} else { } else {
// The current section is not full, append the element.
// The element which is not the first one in the section // The element which is not the first one in the section
// is encoded using the value difference from the preceding // is encoded using the value difference from the preceding
// element. // element.
n := binary.PutUvarint(b.scratch[0:], id-b.desc.max) b.data = binary.AppendUvarint(b.data, id-b.desc.max)
b.data = append(b.data, b.scratch[:n]...)
} }
b.desc.entries++ b.desc.entries++
// The state history ID must be greater than 0.
//if b.desc.min == 0 {
// b.desc.min = id
//}
b.desc.max = id b.desc.max = id
return nil return nil
} }
@ -392,11 +380,10 @@ func (b *blockWriter) full() bool {
// //
// This function is safe to be called multiple times. // This function is safe to be called multiple times.
func (b *blockWriter) finish() []byte { func (b *blockWriter) finish() []byte {
var buf []byte buf := make([]byte, len(b.restarts)*2+1)
for _, number := range b.restarts { for i, restart := range b.restarts {
binary.BigEndian.PutUint16(b.scratch[:2], number) binary.BigEndian.PutUint16(buf[2*i:], restart)
buf = append(buf, b.scratch[:2]...)
} }
buf = append(buf, byte(len(b.restarts))) buf[len(buf)-1] = byte(len(b.restarts))
return append(b.data, buf...) return append(b.data, buf...)
} }

View file

@ -232,3 +232,22 @@ func BenchmarkParseIndexBlock(b *testing.B) {
} }
} }
} }
// BenchmarkBlockWriterAppend benchmarks the performance of indexblock.writer
func BenchmarkBlockWriterAppend(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
desc := newIndexBlockDesc(0)
writer, _ := newBlockWriter(nil, desc)
for i := 0; i < b.N; i++ {
if writer.full() {
desc = newIndexBlockDesc(0)
writer, _ = newBlockWriter(nil, desc)
}
if err := writer.append(writer.desc.max + 1); err != nil {
b.Error(err)
}
}
}