Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(serverv2): add benchmarks of (old) cacheKV vs branch #22497

Merged
merged 5 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 52 additions & 8 deletions server/v2/stf/branch/bench_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package branch

import (
"encoding/binary"
"fmt"
"testing"

Expand All @@ -20,28 +21,65 @@ func Benchmark_CacheStack_Set(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = bs.Set([]byte{0}, []byte{0})
err := bs.Set([]byte{0}, []byte{0})
if err != nil {
b.Fatal(err)
}
}
})
}
}

var sink any

func Benchmark_Get(b *testing.B) {
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = bs.Get([]byte{0})
sink, _ = bs.Get([]byte{0})
}
})
}
if sink == nil {
b.Fatal("benchmark did not run")
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add sink = nil

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sink = nil
}

func Benchmark_Iterate(b *testing.B) {
var keySink, valueSink any
func Benchmark_GetSparse(b *testing.B) {
var sink any
testinginprod marked this conversation as resolved.
Show resolved Hide resolved
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
keys := func() [][]byte {
var keys [][]byte
for i := 0; i < b.N; i++ {
keys = append(keys, numToBytes(i))
}
return keys
}()
b.ResetTimer()
b.ReportAllocs()
for _, key := range keys {
sink, _ = bs.Get(key)
}
})
}
if sink == nil {
b.Fatal("benchmark did not run")
}
sink = nil
}

var (
keySink any
valueSink any
)

func Benchmark_Iterate(b *testing.B) {
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
Expand All @@ -58,9 +96,11 @@ func Benchmark_Iterate(b *testing.B) {
}
})
}

_ = keySink
_ = valueSink
if valueSink == nil || keySink == nil {
b.Fatal("benchmark did not run")
}
valueSink = nil
keySink = nil
}

// makeBranchStack creates a branch stack of the given size and initializes it with unique key-value pairs.
Expand All @@ -71,7 +111,7 @@ func makeBranchStack(b *testing.B, stackSize int) Store[store.KVStore] {
branch = NewStore[store.KVStore](branch)
for j := 0; j < elemsInStack; j++ {
// create unique keys by including the branch index.
key := []byte{byte(i), byte(j)}
key := append(numToBytes(i), numToBytes(j)...)
value := []byte{byte(j)}
err := branch.Set(key, value)
if err != nil {
Expand All @@ -81,3 +121,7 @@ func makeBranchStack(b *testing.B, stackSize int) Store[store.KVStore] {
}
return branch
}

func numToBytes[T ~int](n T) []byte {
return binary.BigEndian.AppendUint64(nil, uint64(n))
}
3 changes: 1 addition & 2 deletions server/v2/stf/branch/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ func (s Store[T]) Get(key []byte) (value []byte, err error) {
if found {
return
}
// after we get it from parent store, we cache it.
// if it is not found in parent store, we still cache it as nil.
// if not found in the changeset, then check the parent.
value, err = s.parent.Get(key)
if err != nil {
return nil, err
Expand Down
120 changes: 120 additions & 0 deletions store/cachekv/branch_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package cachekv_test

import (
"encoding/binary"
"fmt"
"testing"

coretesting "cosmossdk.io/core/testing"
"cosmossdk.io/store/cachekv"
"cosmossdk.io/store/dbadapter"
)

var (
stackSizes = []int{1, 10, 100}
elemsInStack = 10
)

func Benchmark_CacheStack_Set(b *testing.B) {
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
bs.Set([]byte{0}, []byte{0})
}
})
}
}

// Gets the same key from the branch store.
func Benchmark_Get(b *testing.B) {
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sink = bs.Get([]byte{0})
}
})
}
if sink == nil {
b.Fatal("prevent compiler optimization")
}
sink = nil
}
testinginprod marked this conversation as resolved.
Show resolved Hide resolved

// Gets always different keys.
func Benchmark_GetSparse(b *testing.B) {
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
keys := func() [][]byte {
var keys [][]byte
for i := 0; i < b.N; i++ {
keys = append(keys, numToBytes(i))
}
return keys
}()
b.ResetTimer()
b.ReportAllocs()
for _, key := range keys {
sink = bs.Get(key)
}
})
}
if sink == nil {
b.Fatal("Benchmark did not run")
}
sink = nil
}

var keySink, valueSink any

func Benchmark_Iterate(b *testing.B) {

for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
iter := bs.Iterator(nil, nil)
for iter.Valid() {
keySink = iter.Key()
valueSink = iter.Value()
iter.Next()
}
_ = iter.Close()
}
})
}

if keySink == nil || valueSink == nil {
b.Fatal("Benchmark did not run")
}
keySink = nil
valueSink = nil
}

// makeBranchStack creates a branch stack of the given size and initializes it with unique key-value pairs.
func makeBranchStack(_ *testing.B, stackSize int) *cachekv.Store {
parent := dbadapter.Store{DB: coretesting.NewMemDB()}
branch := cachekv.NewStore(parent)
for i := 1; i < stackSize; i++ {
branch = cachekv.NewStore(branch)
for j := 0; j < elemsInStack; j++ {
// create unique keys by including the branch index.
key := append(numToBytes(i), numToBytes(j)...)
value := []byte{byte(j)}
branch.Set(key, value)
}
}
return branch
}

func numToBytes[T ~int](n T) []byte {
return binary.BigEndian.AppendUint64(nil, uint64(n))
}
Loading