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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
43 changes: 40 additions & 3 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 @@ -14,29 +15,61 @@ var (
)

func Benchmark_CacheStack_Set(b *testing.B) {
var sink any
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})
sink = bs.Set([]byte{0}, []byte{0})
}
})
}
if sink != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

You want the opposite, if sink == nil

b.Fatal("prevent compiler optimization")
}
}

func Benchmark_Get(b *testing.B) {
var sink any
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("prevent compiler optimization")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use instead b.Fatal("Benchmark did not run")

}
}

func Benchmark_GetSparse(b *testing.B) {
var sink any
Copy link
Collaborator

Choose a reason for hiding this comment

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

You need this sink to be a global to ensure writebarriers and also please reset it to nil after usage.

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("prevent compiler optimization")
}
}

func Benchmark_Iterate(b *testing.B) {
Expand Down Expand Up @@ -71,7 +104,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 +114,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
116 changes: 116 additions & 0 deletions store/cachekv/branch_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
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) {
var sink any
Copy link
Collaborator

Choose a reason for hiding this comment

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

Needs to global and to be reset after use.

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")
}
}

// Gets always different keys.
func Benchmark_GetSparse(b *testing.B) {
var sink any
Copy link
Collaborator

Choose a reason for hiding this comment

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

Needs to be global and reset to nil after usage.

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("prevent compiler optimization")
}
}

func Benchmark_Iterate(b *testing.B) {
var keySink, valueSink any

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()
}
})
}

_ = keySink
_ = valueSink
}

// 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