From 34278a750972156dd46f9aa2718759236534a68c Mon Sep 17 00:00:00 2001 From: jsvisa Date: Mon, 21 Jul 2025 17:22:52 +0800 Subject: [PATCH 1/6] triedb/pathdb: add BenchmarkBlockWriterAppend Signed-off-by: jsvisa --- triedb/pathdb/history_index_block_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/triedb/pathdb/history_index_block_test.go b/triedb/pathdb/history_index_block_test.go index 7b0e362c6691..c251cea2ecb9 100644 --- a/triedb/pathdb/history_index_block_test.go +++ b/triedb/pathdb/history_index_block_test.go @@ -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) + } + } +} From 125e933da1ea370c0a87e4859e2e6e8b85d31fe2 Mon Sep 17 00:00:00 2001 From: jsvisa Date: Mon, 21 Jul 2025 17:30:01 +0800 Subject: [PATCH 2/6] triedb/pathdb: use binary.append to eliminate the tmp slice Signed-off-by: jsvisa --- triedb/pathdb/history_index_block.go | 30 ++++++++++++---------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/triedb/pathdb/history_index_block.go b/triedb/pathdb/history_index_block.go index 10cc88ed4ed2..91ef71ec2537 100644 --- a/triedb/pathdb/history_index_block.go +++ b/triedb/pathdb/history_index_block.go @@ -221,17 +221,14 @@ func (br *blockReader) readGreaterThan(id uint64) (uint64, error) { type blockWriter struct { desc *indexBlockDesc // Descriptor of the block 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 } func newBlockWriter(blob []byte, desc *indexBlockDesc) (*blockWriter, error) { - scratch := make([]byte, binary.MaxVarintLen64) if len(blob) == 0 { return &blockWriter{ - desc: desc, - scratch: scratch, - data: make([]byte, 0, 1024), + desc: desc, + data: make([]byte, 0, 1024), }, nil } restarts, data, err := parseIndexBlock(blob) @@ -241,7 +238,6 @@ func newBlockWriter(blob []byte, desc *indexBlockDesc) (*blockWriter, error) { return &blockWriter{ desc: desc, restarts: restarts, - scratch: scratch, data: data, // safe to own the slice }, nil } @@ -268,15 +264,12 @@ func (b *blockWriter) append(id uint64) error { // // The first element in a restart range is encoded using its // full value. - n := binary.PutUvarint(b.scratch[0:], id) - b.data = append(b.data, b.scratch[:n]...) + b.data = binary.AppendUvarint(b.data, id) } else { - // The current section is not full, append the element. // The element which is not the first one in the section // is encoded using the value difference from the preceding // element. - n := binary.PutUvarint(b.scratch[0:], id-b.desc.max) - b.data = append(b.data, b.scratch[:n]...) + b.data = binary.AppendUvarint(b.data, id-b.desc.max) } b.desc.entries++ @@ -392,11 +385,14 @@ func (b *blockWriter) full() bool { // // This function is safe to be called multiple times. func (b *blockWriter) finish() []byte { - var buf []byte - for _, number := range b.restarts { - binary.BigEndian.PutUint16(b.scratch[:2], number) - buf = append(buf, b.scratch[:2]...) + restartsLen := len(b.restarts) + buf := make([]byte, len(b.data)+restartsLen*2+1) + copy(buf, b.data) + + restartsOffset := len(b.data) + for i, restart := range b.restarts { + binary.BigEndian.PutUint16(buf[restartsOffset+2*i:], restart) } - buf = append(buf, byte(len(b.restarts))) - return append(b.data, buf...) + buf[len(buf)-1] = byte(restartsLen) + return buf } From a35b45d1d7fd95480417be6726454c9e9326e7da Mon Sep 17 00:00:00 2001 From: jsvisa Date: Mon, 21 Jul 2025 17:30:33 +0800 Subject: [PATCH 3/6] no min Signed-off-by: jsvisa --- triedb/pathdb/history_index_block.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/triedb/pathdb/history_index_block.go b/triedb/pathdb/history_index_block.go index 91ef71ec2537..dab2b560a27d 100644 --- a/triedb/pathdb/history_index_block.go +++ b/triedb/pathdb/history_index_block.go @@ -272,11 +272,6 @@ func (b *blockWriter) append(id uint64) error { b.data = binary.AppendUvarint(b.data, id-b.desc.max) } 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 return nil } From dc12b75db66daa7289ce061ab6fa43a68945aa7b Mon Sep 17 00:00:00 2001 From: jsvisa Date: Tue, 22 Jul 2025 11:47:59 +0800 Subject: [PATCH 4/6] no copy if cap is enough Signed-off-by: jsvisa --- triedb/pathdb/history_index_block.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/triedb/pathdb/history_index_block.go b/triedb/pathdb/history_index_block.go index dab2b560a27d..f13f3d3a0826 100644 --- a/triedb/pathdb/history_index_block.go +++ b/triedb/pathdb/history_index_block.go @@ -381,8 +381,17 @@ func (b *blockWriter) full() bool { // This function is safe to be called multiple times. func (b *blockWriter) finish() []byte { restartsLen := len(b.restarts) - buf := make([]byte, len(b.data)+restartsLen*2+1) - copy(buf, b.data) + extra := restartsLen*2 + 1 + var buf []byte + + if cap(b.data)-len(b.data) >= extra { + // Enough capacity, just reslice; data is already in place. + buf = b.data[:len(b.data)+extra] + } else { + // Not enough capacity, allocate and copy. + buf = make([]byte, len(b.data)+extra) + copy(buf, b.data) + } restartsOffset := len(b.data) for i, restart := range b.restarts { From fe7ae659858d88550fb3271c786c223f44875ab1 Mon Sep 17 00:00:00 2001 From: jsvisa Date: Tue, 22 Jul 2025 11:56:32 +0800 Subject: [PATCH 5/6] more clear Signed-off-by: jsvisa --- triedb/pathdb/history_index_block.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/triedb/pathdb/history_index_block.go b/triedb/pathdb/history_index_block.go index f13f3d3a0826..a4393b97b505 100644 --- a/triedb/pathdb/history_index_block.go +++ b/triedb/pathdb/history_index_block.go @@ -380,9 +380,12 @@ func (b *blockWriter) full() bool { // // This function is safe to be called multiple times. func (b *blockWriter) finish() []byte { - restartsLen := len(b.restarts) - extra := restartsLen*2 + 1 - var buf []byte + var ( + restartsLen = len(b.restarts) + restartsOff = len(b.data) + extra = restartsLen*2 + 1 + buf []byte + ) if cap(b.data)-len(b.data) >= extra { // Enough capacity, just reslice; data is already in place. @@ -393,9 +396,8 @@ func (b *blockWriter) finish() []byte { copy(buf, b.data) } - restartsOffset := len(b.data) for i, restart := range b.restarts { - binary.BigEndian.PutUint16(buf[restartsOffset+2*i:], restart) + binary.BigEndian.PutUint16(buf[restartsOff+2*i:], restart) } buf[len(buf)-1] = byte(restartsLen) return buf From 2f98e38959398f5c3a22636966dbe1d581e47c4a Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Tue, 22 Jul 2025 14:53:32 +0800 Subject: [PATCH 6/6] triedb/pathdb: simplify finish function in block writer --- triedb/pathdb/history_index_block.go | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/triedb/pathdb/history_index_block.go b/triedb/pathdb/history_index_block.go index a4393b97b505..7648b99226c9 100644 --- a/triedb/pathdb/history_index_block.go +++ b/triedb/pathdb/history_index_block.go @@ -380,25 +380,10 @@ func (b *blockWriter) full() bool { // // This function is safe to be called multiple times. func (b *blockWriter) finish() []byte { - var ( - restartsLen = len(b.restarts) - restartsOff = len(b.data) - extra = restartsLen*2 + 1 - buf []byte - ) - - if cap(b.data)-len(b.data) >= extra { - // Enough capacity, just reslice; data is already in place. - buf = b.data[:len(b.data)+extra] - } else { - // Not enough capacity, allocate and copy. - buf = make([]byte, len(b.data)+extra) - copy(buf, b.data) - } - + buf := make([]byte, len(b.restarts)*2+1) for i, restart := range b.restarts { - binary.BigEndian.PutUint16(buf[restartsOff+2*i:], restart) + binary.BigEndian.PutUint16(buf[2*i:], restart) } - buf[len(buf)-1] = byte(restartsLen) - return buf + buf[len(buf)-1] = byte(len(b.restarts)) + return append(b.data, buf...) }