Skip to content

Commit

Permalink
perf: Speedup cachekv iterator on large deletions & IBC v2 upgrade lo…
Browse files Browse the repository at this point in the history
…gic (backport cosmos#10741) (cosmos#10744)

* perf: Speedup cachekv iterator on large deletions & IBC v2 upgrade logic (cosmos#10741)

(cherry picked from commit 314e1d5)

# Conflicts:
#	CHANGELOG.md
#	store/cachekv/store_bench_test.go

* fix conflicts

* add helpers

Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
Co-authored-by: marbar3778 <marbar3778@yahoo.com>
  • Loading branch information
3 people authored and JeancarloBarrios committed Sep 28, 2024
1 parent c0e30f5 commit 271f3f1
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (store) [#10218](https://github.com/cosmos/cosmos-sdk/pull/10218) Charge gas even when there are no entries while seeking.
* (store) [#10247](https://github.com/cosmos/cosmos-sdk/pull/10247) Charge gas for the key length in gas meter.

### Improvements

* (store) [\#10741](https://github.com/cosmos/cosmos-sdk/pull/10741) Significantly speedup iterator creation after delete heavy workloads. Significantly improves IBC migration times.

## [v0.44.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.44.5) - 2021-12-02

### Improvements
Expand Down
2 changes: 1 addition & 1 deletion store/cachekv/bench_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func generateSequentialKeys(startKey []byte, numKeys int) [][]byte {
}

// Generate many random, unsorted keys
func generateRandomKeys(keySize, numKeys int) [][]byte {
func generateRandomKeys(keySize int, numKeys int) [][]byte {
toReturn := make([][]byte, 0, numKeys)
for i := 0; i < numKeys; i++ {
newKey := randSlice(keySize)
Expand Down
29 changes: 10 additions & 19 deletions store/cachekv/store_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ const defaultValueSizeBz = 1 << 12

// This benchmark measures the time of iterator.Next() when the parent store is blank
func benchmarkBlankParentIteratorNext(b *testing.B, keysize int) {
b.Helper()
mem := dbadapter.Store{DB: coretesting.NewMemDB()}
mem := dbadapter.Store{DB: dbm.NewMemDB()}
kvstore := cachekv.NewStore(mem)
// Use a singleton for value, to not waste time computing it
value := randSlice(defaultValueSizeBz)
Expand All @@ -35,17 +34,15 @@ func benchmarkBlankParentIteratorNext(b *testing.B, keysize int) {
iter := kvstore.Iterator(keys[0], keys[b.N])
defer iter.Close()

for ; iter.Valid(); iter.Next() {
_ = iter.Key()
for _ = iter.Key(); iter.Valid(); iter.Next() {
// deadcode elimination stub
sink = iter
}
}

// Benchmark setting New keys to a store, where the new keys are in sequence.
func benchmarkBlankParentAppend(b *testing.B, keysize int) {
b.Helper()
mem := dbadapter.Store{DB: coretesting.NewMemDB()}
mem := dbadapter.Store{DB: dbm.NewMemDB()}
kvstore := cachekv.NewStore(mem)

// Use a singleton for value, to not waste time computing it
Expand All @@ -67,14 +64,12 @@ func benchmarkBlankParentAppend(b *testing.B, keysize int) {
// Benchmark setting New keys to a store, where the new keys are random.
// the speed of this function does not depend on the values in the parent store
func benchmarkRandomSet(b *testing.B, keysize int) {
b.Helper()
mem := dbadapter.Store{DB: coretesting.NewMemDB()}
mem := dbadapter.Store{DB: dbm.NewMemDB()}
kvstore := cachekv.NewStore(mem)

// Use a singleton for value, to not waste time computing it
value := randSlice(defaultValueSizeBz)
// Add 1 to avoid issues when b.N = 1
keys := generateRandomKeys(keysize, b.N+1)
keys := generateRandomKeys(keysize, b.N)

b.ReportAllocs()
b.ResetTimer()
Expand All @@ -86,8 +81,7 @@ func benchmarkRandomSet(b *testing.B, keysize int) {
iter := kvstore.Iterator(keys[0], keys[b.N])
defer iter.Close()

for ; iter.Valid(); iter.Next() {
_ = iter.Key()
for _ = iter.Key(); iter.Valid(); iter.Next() {
// deadcode elimination stub
sink = iter
}
Expand All @@ -98,16 +92,14 @@ func benchmarkRandomSet(b *testing.B, keysize int) {
// We essentially are benchmarking the cacheKV iterator creation & iteration times
// with the number of entries deleted in the parent.
func benchmarkIteratorOnParentWithManyDeletes(b *testing.B, numDeletes int) {
b.Helper()
mem := dbadapter.Store{DB: coretesting.NewMemDB()}
mem := dbadapter.Store{DB: dbm.NewMemDB()}

// Use a singleton for value, to not waste time computing it
value := randSlice(32)
// Use simple values for keys, pick a random start,
// and take next D keys sequentially after.
startKey := randSlice(32)
// Add 1 to avoid issues when numDeletes = 1
keys := generateSequentialKeys(startKey, numDeletes+1)
keys := generateSequentialKeys(startKey, numDeletes)
// setup parent db with D keys.
for _, k := range keys {
mem.Set(k, value)
Expand All @@ -125,11 +117,10 @@ func benchmarkIteratorOnParentWithManyDeletes(b *testing.B, numDeletes int) {
b.ReportAllocs()
b.ResetTimer()

iter := kvstore.Iterator(keys[0], keys[numDeletes])
iter := kvstore.Iterator(keys[0], keys[b.N])
defer iter.Close()

for ; iter.Valid(); iter.Next() {
_ = iter.Key()
for _ = iter.Key(); iter.Valid(); iter.Next() {
// deadcode elimination stub
sink = iter
}
Expand Down

0 comments on commit 271f3f1

Please sign in to comment.