github.com/MetalBlockchain/metalgo@v1.11.9/database/benchmark_database.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package database 5 6 import ( 7 "math/rand" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/MetalBlockchain/metalgo/utils/units" 13 ) 14 15 var ( 16 // Benchmarks is a list of all database benchmarks 17 Benchmarks = map[string]func(b *testing.B, db Database, keys, values [][]byte){ 18 "Get": BenchmarkGet, 19 "Put": BenchmarkPut, 20 "Delete": BenchmarkDelete, 21 "BatchPut": BenchmarkBatchPut, 22 "BatchDelete": BenchmarkBatchDelete, 23 "BatchWrite": BenchmarkBatchWrite, 24 "ParallelGet": BenchmarkParallelGet, 25 "ParallelPut": BenchmarkParallelPut, 26 "ParallelDelete": BenchmarkParallelDelete, 27 } 28 // BenchmarkSizes to use with each benchmark 29 BenchmarkSizes = [][]int{ 30 // count, keySize, valueSize 31 {1024, 32, 32}, 32 {1024, 256, 256}, 33 {1024, 2 * units.KiB, 2 * units.KiB}, 34 } 35 ) 36 37 // Writes size data into the db in order to setup reads in subsequent tests. 38 func SetupBenchmark(b *testing.B, count int, keySize, valueSize int) ([][]byte, [][]byte) { 39 require := require.New(b) 40 41 b.Helper() 42 43 keys := make([][]byte, count) 44 values := make([][]byte, count) 45 for i := 0; i < count; i++ { 46 keyBytes := make([]byte, keySize) 47 valueBytes := make([]byte, valueSize) 48 _, err := rand.Read(keyBytes) // #nosec G404 49 require.NoError(err) 50 _, err = rand.Read(valueBytes) // #nosec G404 51 require.NoError(err) 52 keys[i], values[i] = keyBytes, valueBytes 53 } 54 return keys, values 55 } 56 57 // BenchmarkGet measures the time it takes to get an operation from a database. 58 func BenchmarkGet(b *testing.B, db Database, keys, values [][]byte) { 59 require.NotEmpty(b, keys) 60 count := len(keys) 61 62 require := require.New(b) 63 64 for i, key := range keys { 65 value := values[i] 66 require.NoError(db.Put(key, value)) 67 } 68 69 b.ResetTimer() 70 71 // Reads b.N values from the db 72 for i := 0; i < b.N; i++ { 73 _, err := db.Get(keys[i%count]) 74 require.NoError(err) 75 } 76 } 77 78 // BenchmarkPut measures the time it takes to write an operation to a database. 79 func BenchmarkPut(b *testing.B, db Database, keys, values [][]byte) { 80 require.NotEmpty(b, keys) 81 count := len(keys) 82 83 // Writes b.N values to the db 84 for i := 0; i < b.N; i++ { 85 require.NoError(b, db.Put(keys[i%count], values[i%count])) 86 } 87 } 88 89 // BenchmarkDelete measures the time it takes to delete a (k, v) from a database. 90 func BenchmarkDelete(b *testing.B, db Database, keys, values [][]byte) { 91 require.NotEmpty(b, keys) 92 count := len(keys) 93 94 require := require.New(b) 95 96 // Writes random values of size _size_ to the database 97 for i, key := range keys { 98 value := values[i] 99 require.NoError(db.Put(key, value)) 100 } 101 102 b.ResetTimer() 103 104 // Deletes b.N values from the db 105 for i := 0; i < b.N; i++ { 106 require.NoError(db.Delete(keys[i%count])) 107 } 108 } 109 110 // BenchmarkBatchPut measures the time it takes to batch put. 111 func BenchmarkBatchPut(b *testing.B, db Database, keys, values [][]byte) { 112 require.NotEmpty(b, keys) 113 count := len(keys) 114 115 batch := db.NewBatch() 116 for i := 0; i < b.N; i++ { 117 require.NoError(b, batch.Put(keys[i%count], values[i%count])) 118 } 119 } 120 121 // BenchmarkBatchDelete measures the time it takes to batch delete. 122 func BenchmarkBatchDelete(b *testing.B, db Database, keys, _ [][]byte) { 123 require.NotEmpty(b, keys) 124 count := len(keys) 125 126 batch := db.NewBatch() 127 for i := 0; i < b.N; i++ { 128 require.NoError(b, batch.Delete(keys[i%count])) 129 } 130 } 131 132 // BenchmarkBatchWrite measures the time it takes to batch write. 133 func BenchmarkBatchWrite(b *testing.B, db Database, keys, values [][]byte) { 134 require.NotEmpty(b, keys) 135 136 require := require.New(b) 137 138 batch := db.NewBatch() 139 for i, key := range keys { 140 value := values[i] 141 require.NoError(batch.Put(key, value)) 142 } 143 144 b.ResetTimer() 145 146 for i := 0; i < b.N; i++ { 147 require.NoError(batch.Write()) 148 } 149 } 150 151 // BenchmarkParallelGet measures the time it takes to read in parallel. 152 func BenchmarkParallelGet(b *testing.B, db Database, keys, values [][]byte) { 153 require.NotEmpty(b, keys) 154 count := len(keys) 155 156 require := require.New(b) 157 158 for i, key := range keys { 159 value := values[i] 160 require.NoError(db.Put(key, value)) 161 } 162 163 b.ResetTimer() 164 165 b.RunParallel(func(pb *testing.PB) { 166 for i := 0; pb.Next(); i++ { 167 _, err := db.Get(keys[i%count]) 168 require.NoError(err) 169 } 170 }) 171 } 172 173 // BenchmarkParallelPut measures the time it takes to write to the db in parallel. 174 func BenchmarkParallelPut(b *testing.B, db Database, keys, values [][]byte) { 175 require.NotEmpty(b, keys) 176 count := len(keys) 177 178 b.RunParallel(func(pb *testing.PB) { 179 // Write N values to the db 180 for i := 0; pb.Next(); i++ { 181 require.NoError(b, db.Put(keys[i%count], values[i%count])) 182 } 183 }) 184 } 185 186 // BenchmarkParallelDelete measures the time it takes to delete a (k, v) from the db. 187 func BenchmarkParallelDelete(b *testing.B, db Database, keys, values [][]byte) { 188 require.NotEmpty(b, keys) 189 count := len(keys) 190 191 require := require.New(b) 192 for i, key := range keys { 193 value := values[i] 194 require.NoError(db.Put(key, value)) 195 } 196 b.ResetTimer() 197 198 b.RunParallel(func(pb *testing.PB) { 199 // Deletes b.N values from the db 200 for i := 0; pb.Next(); i++ { 201 require.NoError(db.Delete(keys[i%count])) 202 } 203 }) 204 }