github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/prolly/benchmark/benchmark_read_test.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package benchmark 16 17 import ( 18 "context" 19 "fmt" 20 "math/rand" 21 "sync" 22 "testing" 23 24 "github.com/stretchr/testify/require" 25 26 "github.com/dolthub/dolt/go/store/val" 27 ) 28 29 func BenchmarkMapGet(b *testing.B) { 30 b.Run("benchmark maps 10k", func(b *testing.B) { 31 benchmarkProllyMapGet(b, 10_000) 32 benchmarkTypesMapGet(b, 10_000) 33 }) 34 b.Run("benchmark maps 100k", func(b *testing.B) { 35 benchmarkProllyMapGet(b, 100_000) 36 benchmarkTypesMapGet(b, 100_000) 37 }) 38 b.Run("benchmark maps 1M", func(b *testing.B) { 39 benchmarkProllyMapGet(b, 1_000_000) 40 benchmarkTypesMapGet(b, 1_000_000) 41 }) 42 } 43 44 func BenchmarkStepMapGet(b *testing.B) { 45 b.Skip() 46 step := uint64(100_000) 47 for sz := step; sz < step*20; sz += step { 48 nm := fmt.Sprintf("benchmark maps %d", sz) 49 b.Run(nm, func(b *testing.B) { 50 benchmarkProllyMapGet(b, sz) 51 benchmarkTypesMapGet(b, sz) 52 }) 53 } 54 } 55 56 func BenchmarkParallelMapGet(b *testing.B) { 57 b.Run("benchmark maps 10k", func(b *testing.B) { 58 benchmarkProllyMapGetParallel(b, 10_000) 59 benchmarkTypesMapGetParallel(b, 10_000) 60 }) 61 b.Run("benchmark maps 100k", func(b *testing.B) { 62 benchmarkProllyMapGetParallel(b, 100_000) 63 benchmarkTypesMapGetParallel(b, 100_000) 64 }) 65 b.Run("benchmark maps 1M", func(b *testing.B) { 66 benchmarkProllyMapGetParallel(b, 1_000_000) 67 benchmarkTypesMapGetParallel(b, 1_000_000) 68 }) 69 } 70 71 func BenchmarkStepParallelMapGet(b *testing.B) { 72 b.Skip() 73 step := uint64(100_000) 74 for sz := step; sz < step*20; sz += step { 75 nm := fmt.Sprintf("benchmark maps parallel %d", sz) 76 b.Run(nm, func(b *testing.B) { 77 benchmarkProllyMapGetParallel(b, sz) 78 benchmarkTypesMapGetParallel(b, sz) 79 }) 80 } 81 } 82 83 func BenchmarkGetLargeProlly(b *testing.B) { 84 benchmarkProllyMapGet(b, 1_000_000) 85 } 86 87 func BenchmarkGetLargeNoms(b *testing.B) { 88 benchmarkTypesMapGet(b, 1_000_000) 89 } 90 91 func BenchmarkGetLargeBBolt(b *testing.B) { 92 benchmarkBBoltMapGet(b, 1_000_000) 93 } 94 95 func BenchmarkProllyParallelGetLarge(b *testing.B) { 96 benchmarkProllyMapGetParallel(b, 1_000_000) 97 } 98 99 func BenchmarkNomsParallelGetLarge(b *testing.B) { 100 benchmarkTypesMapGetParallel(b, 1_000_000) 101 } 102 103 func benchmarkProllyMapGet(b *testing.B, size uint64) { 104 bench := generateProllyBench(b, size) 105 b.ResetTimer() 106 b.Run("benchmark new format reads", func(b *testing.B) { 107 ctx := context.Background() 108 109 for i := 0; i < b.N; i++ { 110 idx := rand.Uint64() % uint64(len(bench.tups)) 111 key := bench.tups[idx][0] 112 _ = bench.m.Get(ctx, key, func(_, _ val.Tuple) (e error) { 113 return 114 }) 115 } 116 b.ReportAllocs() 117 }) 118 } 119 120 func benchmarkTypesMapGet(b *testing.B, size uint64) { 121 bench := generateTypesBench(b, size) 122 b.ResetTimer() 123 b.Run("benchmark old format reads", func(b *testing.B) { 124 ctx := context.Background() 125 for i := 0; i < b.N; i++ { 126 idx := rand.Uint64() % uint64(len(bench.tups)) 127 _, _, _ = bench.m.MaybeGet(ctx, bench.tups[idx][0]) 128 } 129 b.ReportAllocs() 130 }) 131 } 132 133 func benchmarkBBoltMapGet(b *testing.B, size uint64) { 134 bench := generateBBoltBench(b, size) 135 b.ResetTimer() 136 b.Run("benchmark bbolt reads", func(b *testing.B) { 137 tx, err := bench.db.Begin(false) 138 require.NoError(b, err) 139 bck := tx.Bucket(bucket) 140 141 for i := 0; i < b.N; i++ { 142 idx := rand.Uint64() % uint64(len(bench.tups)) 143 key := bench.tups[idx][0] 144 _ = bck.Get(key) 145 } 146 b.ReportAllocs() 147 }) 148 } 149 150 func benchmarkProllyMapGetParallel(b *testing.B, size uint64) { 151 bench := generateProllyBench(b, size) 152 b.Run(fmt.Sprintf("benchmark new format %d", size), func(b *testing.B) { 153 b.RunParallel(func(b *testing.PB) { 154 ctx := context.Background() 155 rnd := rand.NewSource(0) 156 for b.Next() { 157 idx := int(rnd.Int63()) % len(bench.tups) 158 key := bench.tups[idx][0] 159 _ = bench.m.Get(ctx, key, func(_, _ val.Tuple) (e error) { 160 return 161 }) 162 } 163 }) 164 b.ReportAllocs() 165 }) 166 } 167 168 func benchmarkTypesMapGetParallel(b *testing.B, size uint64) { 169 bench := generateTypesBench(b, size) 170 b.Run(fmt.Sprintf("benchmark old format %d", size), func(b *testing.B) { 171 b.RunParallel(func(pb *testing.PB) { 172 ctx := context.Background() 173 rnd := rand.NewSource(0) 174 for pb.Next() { 175 idx := int(rnd.Int63()) % len(bench.tups) 176 _, _, _ = bench.m.MaybeGet(ctx, bench.tups[idx][0]) 177 } 178 }) 179 b.ReportAllocs() 180 }) 181 } 182 183 const mapScale = 4096 184 185 func BenchmarkGoMapGet(b *testing.B) { 186 b.Skip() 187 kv1 := makeGoMap(mapScale) 188 kv2 := makeSyncMap(mapScale) 189 b.ResetTimer() 190 191 b.Run("test golang map", func(b *testing.B) { 192 for j := 0; j < b.N; j++ { 193 _, ok := kv1[uint64(j%mapScale)] 194 if !ok { 195 b.Fail() 196 } 197 } 198 b.ReportAllocs() 199 }) 200 b.Run("test golang sync map", func(b *testing.B) { 201 for j := 0; j < b.N; j++ { 202 _, ok := kv2.Load(uint64(j % mapScale)) 203 if !ok { 204 b.Fail() 205 } 206 } 207 b.ReportAllocs() 208 }) 209 } 210 211 func BenchmarkParallelGoMapGet(b *testing.B) { 212 b.Skip() 213 kv1 := makeGoMap(mapScale) 214 kv2 := makeSyncMap(mapScale) 215 b.ResetTimer() 216 217 b.Run("test golang map", func(b *testing.B) { 218 b.RunParallel(func(pb *testing.PB) { 219 j := 0 220 for pb.Next() { 221 _, _ = kv1[uint64(j%mapScale)] 222 j++ 223 } 224 }) 225 b.ReportAllocs() 226 }) 227 b.Run("test golang sync map", func(b *testing.B) { 228 b.RunParallel(func(pb *testing.PB) { 229 v, _ := kv2.Load(uint64(1234)) 230 tup := v.(val.Tuple) 231 j := 0 232 for pb.Next() { 233 k := uint64(j % mapScale) 234 if j%10 == 0 { 235 kv2.Store(k, tup) 236 } else { 237 _, _ = kv2.Load(k) 238 } 239 j++ 240 } 241 }) 242 b.ReportAllocs() 243 }) 244 } 245 246 func makeGoMap(scale uint64) map[uint64]val.Tuple { 247 src := rand.NewSource(0) 248 vb := val.NewTupleBuilder(val.NewTupleDescriptor( 249 val.Type{Enc: val.Int64Enc, Nullable: true}, 250 val.Type{Enc: val.Int64Enc, Nullable: true}, 251 val.Type{Enc: val.Int64Enc, Nullable: true}, 252 val.Type{Enc: val.Int64Enc, Nullable: true}, 253 val.Type{Enc: val.Int64Enc, Nullable: true}, 254 )) 255 256 kv := make(map[uint64]val.Tuple, scale) 257 for i := uint64(0); i < scale; i++ { 258 vb.PutInt64(0, src.Int63()) 259 vb.PutInt64(1, src.Int63()) 260 vb.PutInt64(2, src.Int63()) 261 vb.PutInt64(3, src.Int63()) 262 vb.PutInt64(4, src.Int63()) 263 kv[i] = vb.Build(shared) 264 } 265 return kv 266 } 267 268 func makeSyncMap(scale uint64) *sync.Map { 269 src := rand.NewSource(0) 270 vb := val.NewTupleBuilder(val.NewTupleDescriptor( 271 val.Type{Enc: val.Int64Enc, Nullable: true}, 272 val.Type{Enc: val.Int64Enc, Nullable: true}, 273 val.Type{Enc: val.Int64Enc, Nullable: true}, 274 val.Type{Enc: val.Int64Enc, Nullable: true}, 275 val.Type{Enc: val.Int64Enc, Nullable: true}, 276 )) 277 kv := &sync.Map{} 278 279 for i := uint64(0); i < scale; i++ { 280 vb.PutInt64(0, src.Int63()) 281 vb.PutInt64(1, src.Int63()) 282 vb.PutInt64(2, src.Int63()) 283 vb.PutInt64(3, src.Int63()) 284 vb.PutInt64(4, src.Int63()) 285 kv.Store(i, vb.Build(shared)) 286 } 287 return kv 288 }