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