github.com/Finschia/finschia-sdk@v0.48.1/store/cachekv/store_bench_test.go (about)

     1  package cachekv_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	dbm "github.com/tendermint/tm-db"
     7  
     8  	"github.com/Finschia/finschia-sdk/store/cachekv"
     9  	"github.com/Finschia/finschia-sdk/store/dbadapter"
    10  )
    11  
    12  var sink interface{}
    13  
    14  const defaultValueSizeBz = 1 << 12
    15  
    16  // This benchmark measures the time of iterator.Next() when the parent store is blank
    17  func benchmarkBlankParentIteratorNext(b *testing.B, keysize int) {
    18  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    19  	kvstore := cachekv.NewStore(mem)
    20  	// Use a singleton for value, to not waste time computing it
    21  	value := randSlice(defaultValueSizeBz)
    22  	// Use simple values for keys, pick a random start,
    23  	// and take next b.N keys sequentially after.]
    24  	startKey := randSlice(32)
    25  
    26  	// Add 1 to avoid issues when b.N = 1
    27  	keys := generateSequentialKeys(startKey, b.N+1)
    28  	for _, k := range keys {
    29  		kvstore.Set(k, value)
    30  	}
    31  
    32  	b.ReportAllocs()
    33  	b.ResetTimer()
    34  
    35  	iter := kvstore.Iterator(keys[0], keys[b.N])
    36  	defer iter.Close()
    37  
    38  	for _ = iter.Key(); iter.Valid(); iter.Next() {
    39  		// deadcode elimination stub
    40  		sink = iter
    41  	}
    42  }
    43  
    44  // Benchmark setting New keys to a store, where the new keys are in sequence.
    45  func benchmarkBlankParentAppend(b *testing.B, keysize int) {
    46  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    47  	kvstore := cachekv.NewStore(mem)
    48  
    49  	// Use a singleton for value, to not waste time computing it
    50  	value := randSlice(32)
    51  	// Use simple values for keys, pick a random start,
    52  	// and take next b.N keys sequentially after.
    53  	startKey := randSlice(32)
    54  
    55  	keys := generateSequentialKeys(startKey, b.N)
    56  
    57  	b.ReportAllocs()
    58  	b.ResetTimer()
    59  
    60  	for _, k := range keys {
    61  		kvstore.Set(k, value)
    62  	}
    63  }
    64  
    65  // Benchmark setting New keys to a store, where the new keys are random.
    66  // the speed of this function does not depend on the values in the parent store
    67  func benchmarkRandomSet(b *testing.B, keysize int) {
    68  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    69  	kvstore := cachekv.NewStore(mem)
    70  
    71  	// Use a singleton for value, to not waste time computing it
    72  	value := randSlice(defaultValueSizeBz)
    73  	keys := generateRandomKeys(keysize, b.N)
    74  
    75  	b.ReportAllocs()
    76  	b.ResetTimer()
    77  
    78  	for _, k := range keys {
    79  		kvstore.Set(k, value)
    80  	}
    81  
    82  	iter := kvstore.Iterator(nil, nil)
    83  	defer iter.Close()
    84  
    85  	for _ = iter.Key(); iter.Valid(); iter.Next() {
    86  		// deadcode elimination stub
    87  		sink = iter
    88  	}
    89  }
    90  
    91  // Benchmark creating an iterator on a parent with D entries,
    92  // that are all deleted in the cacheKV store.
    93  // We essentially are benchmarking the cacheKV iterator creation & iteration times
    94  // with the number of entries deleted in the parent.
    95  func benchmarkIteratorOnParentWithManyDeletes(b *testing.B, numDeletes int) {
    96  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    97  
    98  	// Use a singleton for value, to not waste time computing it
    99  	value := randSlice(32)
   100  	// Use simple values for keys, pick a random start,
   101  	// and take next D keys sequentially after.
   102  	startKey := randSlice(32)
   103  	keys := generateSequentialKeys(startKey, numDeletes)
   104  	// setup parent db with D keys.
   105  	for _, k := range keys {
   106  		mem.Set(k, value)
   107  	}
   108  	kvstore := cachekv.NewStore(mem)
   109  	// Delete all keys from the cache KV store.
   110  	// The keys[1:] is to keep at least one entry in parent, due to a bug in the SDK iterator design.
   111  	// Essentially the iterator will never be valid, in that it should never run.
   112  	// However, this is incompatible with the for loop structure the SDK uses, hence
   113  	// causes a panic. Thus we do keys[1:].
   114  	for _, k := range keys[1:] {
   115  		kvstore.Delete(k)
   116  	}
   117  
   118  	b.ReportAllocs()
   119  	b.ResetTimer()
   120  
   121  	iter := kvstore.Iterator(keys[0], keys[b.N])
   122  	defer iter.Close()
   123  
   124  	for _ = iter.Key(); iter.Valid(); iter.Next() {
   125  		// deadcode elimination stub
   126  		sink = iter
   127  	}
   128  }
   129  
   130  func BenchmarkBlankParentIteratorNextKeySize32(b *testing.B) {
   131  	benchmarkBlankParentIteratorNext(b, 32)
   132  }
   133  
   134  func BenchmarkBlankParentAppendKeySize32(b *testing.B) {
   135  	benchmarkBlankParentAppend(b, 32)
   136  }
   137  
   138  func BenchmarkSetKeySize32(b *testing.B) {
   139  	benchmarkRandomSet(b, 32)
   140  }
   141  
   142  func BenchmarkIteratorOnParentWith1MDeletes(b *testing.B) {
   143  	benchmarkIteratorOnParentWithManyDeletes(b, 1_000_000)
   144  }