github.com/iotexproject/iotex-core@v1.14.1-rc1/db/trie/mptrie/merklepatriciatrie_benchmark_test.go (about) 1 package mptrie 2 3 import ( 4 "context" 5 "encoding/binary" 6 "fmt" 7 "math/rand" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/iotexproject/iotex-core/db" 13 "github.com/iotexproject/iotex-core/db/batch" 14 "github.com/iotexproject/iotex-core/db/trie" 15 "github.com/iotexproject/iotex-core/testutil" 16 ) 17 18 func BenchmarkTrie_Get(b *testing.B) { benchTrieGet(b, false, false) } 19 func BenchmarkTrie_GetWithAsync(b *testing.B) { benchTrieGet(b, true, false) } 20 func BenchmarkTrie_GetDB(b *testing.B) { benchTrieGet(b, false, true) } 21 func BenchmarkTrie_GetDBWithAsync(b *testing.B) { benchTrieGet(b, true, true) } 22 func BenchmarkTrie_UpsertLE(b *testing.B) { benchTrieUpsert(b, binary.LittleEndian) } 23 func BenchmarkTrie_UpsertBE(b *testing.B) { benchTrieUpsert(b, binary.BigEndian) } 24 25 const ( 26 _benchElemCount = 20000 27 _keyLength = 32 28 ) 29 30 func benchTrieGet(b *testing.B, async, withDB bool) { 31 var ( 32 require = require.New(b) 33 opts = []Option{KeyLengthOption(_keyLength)} 34 flush func() error 35 ) 36 if async { 37 opts = append(opts, AsyncOption()) 38 } 39 if withDB { 40 testPath, err := testutil.PathOfTempFile(fmt.Sprintf("test-kv-store-%t.bolt", async)) 41 require.NoError(err) 42 defer testutil.CleanupPath(testPath) 43 cfg := db.DefaultConfig 44 cfg.DbPath = testPath 45 dao := db.NewBoltDB(cfg) 46 flusher, err := db.NewKVStoreFlusher(dao, batch.NewCachedBatch()) 47 require.NoError(err) 48 flusherKV := flusher.KVStoreWithBuffer() 49 flush = flusher.Flush 50 kvStore, err := trie.NewKVStore("test", flusherKV) 51 require.NoError(err) 52 require.NoError(kvStore.Start(context.Background())) 53 opts = append(opts, KVStoreOption(kvStore)) 54 } 55 tr, err := New(opts...) 56 require.NoError(err) 57 require.NoError(tr.Start(context.Background())) 58 defer require.NoError(tr.Stop(context.Background())) 59 60 key := make([]byte, _keyLength) 61 for i := 0; i < _benchElemCount; i++ { 62 binary.LittleEndian.PutUint64(key, uint64(i)) 63 require.NoError(tr.Upsert(key, key)) 64 } 65 binary.LittleEndian.PutUint64(key, uint64(_benchElemCount)/2) 66 if withDB { 67 require.NoError(flush()) 68 } 69 70 b.ResetTimer() 71 for i := 0; i < b.N; i++ { 72 tr.Get(key) 73 } 74 b.StopTimer() 75 b.ReportAllocs() 76 } 77 78 func benchTrieUpsert(b *testing.B, e binary.ByteOrder) { 79 var ( 80 require = require.New(b) 81 opts = []Option{KeyLengthOption(_keyLength)} 82 ) 83 trie, err := New(opts...) 84 require.NoError(err) 85 require.NoError(trie.Start(context.Background())) 86 defer require.NoError(trie.Stop(context.Background())) 87 k := make([]byte, _keyLength) 88 b.ResetTimer() 89 for i := 0; i < b.N; i++ { 90 e.PutUint64(k, uint64(i)) 91 trie.Upsert(k, k) 92 } 93 b.StopTimer() 94 b.ReportAllocs() 95 } 96 97 func BenchmarkTrie_UpsertWithAsync(b *testing.B) { 98 tr, _, callback := initTrie(2) 99 defer callback() 100 101 keys := [][]byte{} 102 for i := 0; i < 10; i++ { 103 for j := 0; j < 256; j++ { 104 key := []byte{byte(i), byte(j)} 105 keys = append(keys, key) 106 } 107 } 108 109 b.ResetTimer() 110 for n := 0; n < b.N; n++ { 111 for _, v := range keys { 112 tr.Upsert(v, []byte{}) 113 } 114 } 115 } 116 117 func BenchmarkTrie_RootHashWithAsync(b *testing.B) { 118 tr, flush, callback := initTrie(2) 119 defer callback() 120 121 keys := [][]byte{} 122 for i := 0; i < 10; i++ { 123 for j := 0; j < 256; j++ { 124 key := []byte{byte(i), byte(j)} 125 keys = append(keys, key) 126 } 127 } 128 for _, v := range keys { 129 tr.Upsert(v, []byte{}) 130 } 131 tr.RootHash() 132 flush() 133 134 b.ResetTimer() 135 for n := 0; n < b.N; n++ { 136 tr.Upsert(keys[rand.Intn(len(keys))], []byte{}) 137 tr.RootHash() 138 } 139 } 140 141 func initTrie(keyLen int) (trie.Trie, func() error, func()) { 142 testPath, err := testutil.PathOfTempFile("test-kv-store.bolt") 143 if err != nil { 144 panic(err) 145 } 146 cfg := db.DefaultConfig 147 cfg.DbPath = testPath 148 dao := db.NewBoltDB(cfg) 149 flusher, err := db.NewKVStoreFlusher(dao, batch.NewCachedBatch()) 150 if err != nil { 151 panic(err) 152 } 153 flusherKV := flusher.KVStoreWithBuffer() 154 kvStore, err := trie.NewKVStore("test", flusherKV) 155 if err != nil { 156 panic(err) 157 } 158 err = kvStore.Start(context.Background()) 159 if err != nil { 160 panic(err) 161 } 162 opts := []Option{KeyLengthOption(keyLen), AsyncOption(), KVStoreOption(kvStore)} 163 tr, err := New(opts...) 164 if err != nil { 165 panic(err) 166 } 167 err = tr.Start(context.Background()) 168 if err != nil { 169 panic(err) 170 } 171 return tr, flusher.Flush, func() { 172 tr.Stop(context.Background()) 173 testutil.CleanupPath(testPath) 174 } 175 }