cosmos-sdk/store/cachekv/store_bench_test.go
Daniel Wedul 16e5d1a47b
feat(types): Deprecate the DBBackend variable in favor of new app-db-backend config entry (#11188)
* [10948]: Add changelog entry.

* [10948]: Deprecate the types.DBBackend variable and the NewLevelDB function. Create a NewDB function to replace them.

* [10948]: Add a DBBackend string to the simulation config and a flag for setting it. Update the simulation setup to use that instead of the compile-time DBBackend variable.

* [10948]: Update the mock app creator to use the NewDB function. Not sure what to do about the db backend in that case though.

* [10948]: Update changelog to reflect new db-backend field name.

* [10948]: Use the tendermint db-backend type for the snapshot db.

* [10948]: Update the last use of NewLevelDB by adding a parameter to openDB and uppdating calls to that to provide the db type to use.

* [10948]: Upddate the NewDB function to also have a default db backend type if an empty string is provided there.

* [10948]: Remove the new TODO in mock.NewApp. After looking through it's uses, there doesn't seem to be any desire to change it, and there's no easy way to communicate it.

* [10948]: Enhance the NewDB defer function to also add info to any err that is being returned.

* [10948]: Add some unit tests for NewDB.

* [10948]: Lint fixes.

* [10948]: Add a changelog entry to the deprecated section.

* [10948]: Update the makefile to no longer set the types.DBBackend value.

* [10948]: Use memdb for the mock app instead of goleveldb. I know it was a goleveldb before, but for a mock app, a memdb feels like a better choice (assuming 'mock' and 'mem' mean what I assume they mean).

* [10948]: Fix the store benchmark tests (had some index-out-of-range issues).

* [10948]: Fix cachekv store bench test calling iter.Key() before checking iter.Valid().

* [10948]: Remove the panic recovery from types.NewDB since dbm.NewDB returns an error now (it didn't originally, when NewLevelDB was first written).

* [10948]: Add changlog entry indicationg an API breaking change due to the DBBackend change.

* [10948]: Get rid of the types.NewDB function in favor of just using the tm-db version of it.

* [10948]: Fix Update the codeql-analysis github action to use go v1.17.

* [10948]: Add config file option for the app db backend type.

* [10948]: Adjust the comment on the app-db-backend config entry to clarify fallback behavior.

* [10948]: Add a default of GoLevelDBBackend to GetAppDBBackend. The old DBBackend variable defaulted to that, and some unit tests assume that behavior still exists.

* [10948]: Add the missing quotes around the app-db-backend value.

* [10948]: Small tweak to the changelog's deprecated entry.

* Add the go version declaration back into the codeql-analysis github action.

* [10948]: Update new use of openDB.

* [10948]: Put a brief delay after closing the test network. Hopefully that helps with address-in-use and non-empty directory errors.

Co-authored-by: Marko <marbar3778@yahoo.com>
2022-03-18 10:26:20 +01:00

150 lines
4.0 KiB
Go

package cachekv_test
import (
"testing"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/store/cachekv"
"github.com/cosmos/cosmos-sdk/store/dbadapter"
)
var sink interface{}
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) {
mem := dbadapter.Store{DB: dbm.NewMemDB()}
kvstore := cachekv.NewStore(mem)
// Use a singleton for value, to not waste time computing it
value := randSlice(defaultValueSizeBz)
// Use simple values for keys, pick a random start,
// and take next b.N keys sequentially after.]
startKey := randSlice(32)
// Add 1 to avoid issues when b.N = 1
keys := generateSequentialKeys(startKey, b.N+1)
for _, k := range keys {
kvstore.Set(k, value)
}
b.ReportAllocs()
b.ResetTimer()
iter := kvstore.Iterator(keys[0], keys[b.N])
defer iter.Close()
for ; iter.Valid(); iter.Next() {
_ = iter.Key()
// 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) {
mem := dbadapter.Store{DB: dbm.NewMemDB()}
kvstore := cachekv.NewStore(mem)
// 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 b.N keys sequentially after.
startKey := randSlice(32)
keys := generateSequentialKeys(startKey, b.N)
b.ReportAllocs()
b.ResetTimer()
for _, k := range keys {
kvstore.Set(k, value)
}
}
// 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) {
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)
b.ReportAllocs()
b.ResetTimer()
for _, k := range keys {
kvstore.Set(k, value)
}
iter := kvstore.Iterator(keys[0], keys[b.N])
defer iter.Close()
for ; iter.Valid(); iter.Next() {
_ = iter.Key()
// deadcode elimination stub
sink = iter
}
}
// Benchmark creating an iterator on a parent with D entries,
// that are all deleted in the cacheKV store.
// 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) {
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)
// setup parent db with D keys.
for _, k := range keys {
mem.Set(k, value)
}
kvstore := cachekv.NewStore(mem)
// Delete all keys from the cache KV store.
// The keys[1:] is to keep at least one entry in parent, due to a bug in the SDK iterator design.
// Essentially the iterator will never be valid, in that it should never run.
// However, this is incompatible with the for loop structure the SDK uses, hence
// causes a panic. Thus we do keys[1:].
for _, k := range keys[1:] {
kvstore.Delete(k)
}
b.ReportAllocs()
b.ResetTimer()
iter := kvstore.Iterator(keys[0], keys[numDeletes])
defer iter.Close()
for ; iter.Valid(); iter.Next() {
_ = iter.Key()
// deadcode elimination stub
sink = iter
}
}
func BenchmarkBlankParentIteratorNextKeySize32(b *testing.B) {
benchmarkBlankParentIteratorNext(b, 32)
}
func BenchmarkBlankParentAppendKeySize32(b *testing.B) {
benchmarkBlankParentAppend(b, 32)
}
func BenchmarkSetKeySize32(b *testing.B) {
benchmarkRandomSet(b, 32)
}
func BenchmarkIteratorOnParentWith1MDeletes(b *testing.B) {
benchmarkIteratorOnParentWithManyDeletes(b, 1_000_000)
}