github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/storage/bench_rocksdb_test.go (about) 1 // Copyright 2014 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package storage 12 13 import ( 14 "context" 15 "fmt" 16 "math/rand" 17 "testing" 18 19 "github.com/cockroachdb/cockroach/pkg/base" 20 "github.com/cockroachdb/cockroach/pkg/roachpb" 21 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 22 "github.com/cockroachdb/cockroach/pkg/util/encoding" 23 "github.com/cockroachdb/cockroach/pkg/util/hlc" 24 "github.com/cockroachdb/cockroach/pkg/util/randutil" 25 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 26 ) 27 28 func setupMVCCRocksDB(b testing.TB, dir string) Engine { 29 cache := NewRocksDBCache(1 << 30 /* 1GB */) 30 defer cache.Release() 31 32 rocksdb, err := NewRocksDB( 33 RocksDBConfig{ 34 StorageConfig: base.StorageConfig{ 35 Settings: cluster.MakeTestingClusterSettings(), 36 Dir: dir, 37 }, 38 }, 39 cache, 40 ) 41 if err != nil { 42 b.Fatalf("could not create new rocksdb db instance at %s: %+v", dir, err) 43 } 44 return rocksdb 45 } 46 47 func setupMVCCInMemRocksDB(_ testing.TB, loc string) Engine { 48 return newRocksDBInMem(roachpb.Attributes{}, testCacheSize) 49 } 50 51 // Read benchmarks. All of them run with on-disk data. 52 53 func BenchmarkMVCCScan_RocksDB(b *testing.B) { 54 if testing.Short() { 55 b.Skip("TODO: fix benchmark") 56 } 57 58 ctx := context.Background() 59 for _, numRows := range []int{1, 10, 100, 1000, 10000} { 60 b.Run(fmt.Sprintf("rows=%d", numRows), func(b *testing.B) { 61 for _, numVersions := range []int{1, 2, 10, 100} { 62 b.Run(fmt.Sprintf("versions=%d", numVersions), func(b *testing.B) { 63 for _, valueSize := range []int{8, 64, 512} { 64 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 65 runMVCCScan(ctx, b, setupMVCCRocksDB, benchScanOptions{ 66 benchDataOptions: benchDataOptions{ 67 numVersions: numVersions, 68 valueBytes: valueSize, 69 }, 70 numRows: numRows, 71 reverse: false, 72 }) 73 }) 74 } 75 }) 76 } 77 }) 78 } 79 } 80 81 func BenchmarkMVCCReverseScan_RocksDB(b *testing.B) { 82 if testing.Short() { 83 b.Skip("TODO: fix benchmark") 84 } 85 86 ctx := context.Background() 87 for _, numRows := range []int{1, 10, 100, 1000, 10000} { 88 b.Run(fmt.Sprintf("rows=%d", numRows), func(b *testing.B) { 89 for _, numVersions := range []int{1, 2, 10, 100} { 90 b.Run(fmt.Sprintf("versions=%d", numVersions), func(b *testing.B) { 91 for _, valueSize := range []int{8, 64, 512} { 92 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 93 runMVCCScan(ctx, b, setupMVCCRocksDB, benchScanOptions{ 94 benchDataOptions: benchDataOptions{ 95 numVersions: numVersions, 96 valueBytes: valueSize, 97 }, 98 numRows: numRows, 99 reverse: true, 100 }) 101 }) 102 } 103 }) 104 } 105 }) 106 } 107 } 108 109 func BenchmarkMVCCScanTransactionalData_RocksDB(b *testing.B) { 110 ctx := context.Background() 111 runMVCCScan(ctx, b, setupMVCCRocksDB, benchScanOptions{ 112 numRows: 10000, 113 benchDataOptions: benchDataOptions{ 114 numVersions: 2, 115 valueBytes: 8, 116 transactional: true, 117 }, 118 }) 119 } 120 121 func BenchmarkMVCCGet_RocksDB(b *testing.B) { 122 ctx := context.Background() 123 for _, numVersions := range []int{1, 10, 100} { 124 b.Run(fmt.Sprintf("versions=%d", numVersions), func(b *testing.B) { 125 for _, valueSize := range []int{8} { 126 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 127 runMVCCGet(ctx, b, setupMVCCRocksDB, benchDataOptions{ 128 numVersions: numVersions, 129 valueBytes: valueSize, 130 }) 131 }) 132 } 133 }) 134 } 135 } 136 137 func BenchmarkMVCCComputeStats_RocksDB(b *testing.B) { 138 if testing.Short() { 139 b.Skip("short flag") 140 } 141 ctx := context.Background() 142 for _, valueSize := range []int{8, 32, 256} { 143 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 144 runMVCCComputeStats(ctx, b, setupMVCCRocksDB, valueSize) 145 }) 146 } 147 } 148 149 func BenchmarkMVCCFindSplitKey_RocksDB(b *testing.B) { 150 ctx := context.Background() 151 for _, valueSize := range []int{32} { 152 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 153 runMVCCFindSplitKey(ctx, b, setupMVCCRocksDB, valueSize) 154 }) 155 } 156 } 157 158 func BenchmarkIterOnBatch_RocksDB(b *testing.B) { 159 ctx := context.Background() 160 for _, writes := range []int{10, 100, 1000, 10000} { 161 b.Run(fmt.Sprintf("writes=%d", writes), func(b *testing.B) { 162 benchmarkIterOnBatch(ctx, b, writes) 163 }) 164 } 165 } 166 167 // BenchmarkIterOnReadOnly_RocksDB is a microbenchmark that measures the 168 // performance of creating an iterator and seeking to a key if a read-only 169 // ReadWriter that caches the RocksDB iterator is used 170 func BenchmarkIterOnReadOnly_RocksDB(b *testing.B) { 171 for _, writes := range []int{10, 100, 1000, 10000} { 172 b.Run(fmt.Sprintf("writes=%d", writes), func(b *testing.B) { 173 benchmarkIterOnReadWriter(b, writes, Engine.NewReadOnly, true) 174 }) 175 } 176 } 177 178 // BenchmarkIterOnEngine_RocksDB is a microbenchmark that measures the 179 // performance of creating an iterator and seeking to a key without caching is 180 // used (see BenchmarkIterOnIterCacher_RocksDB). 181 func BenchmarkIterOnEngine_RocksDB(b *testing.B) { 182 for _, writes := range []int{10, 100, 1000, 10000} { 183 b.Run(fmt.Sprintf("writes=%d", writes), func(b *testing.B) { 184 benchmarkIterOnReadWriter(b, writes, func(e Engine) ReadWriter { return e }, false) 185 }) 186 } 187 } 188 189 // Write benchmarks. Most of them run in-memory except for DeleteRange benchs, 190 // which make more sense when data is present. 191 192 func BenchmarkMVCCPut_RocksDB(b *testing.B) { 193 ctx := context.Background() 194 for _, valueSize := range []int{10, 100, 1000, 10000} { 195 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 196 runMVCCPut(ctx, b, setupMVCCInMemRocksDB, valueSize) 197 }) 198 } 199 } 200 201 func BenchmarkMVCCBlindPut_RocksDB(b *testing.B) { 202 ctx := context.Background() 203 for _, valueSize := range []int{10, 100, 1000, 10000} { 204 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 205 runMVCCBlindPut(ctx, b, setupMVCCInMemRocksDB, valueSize) 206 }) 207 } 208 } 209 210 func BenchmarkMVCCConditionalPut_RocksDB(b *testing.B) { 211 ctx := context.Background() 212 for _, createFirst := range []bool{false, true} { 213 prefix := "Create" 214 if createFirst { 215 prefix = "Replace" 216 } 217 b.Run(prefix, func(b *testing.B) { 218 for _, valueSize := range []int{10, 100, 1000, 10000} { 219 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 220 runMVCCConditionalPut(ctx, b, setupMVCCInMemRocksDB, valueSize, createFirst) 221 }) 222 } 223 }) 224 } 225 } 226 227 func BenchmarkMVCCBlindConditionalPut_RocksDB(b *testing.B) { 228 ctx := context.Background() 229 for _, valueSize := range []int{10, 100, 1000, 10000} { 230 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 231 runMVCCBlindConditionalPut(ctx, b, setupMVCCInMemRocksDB, valueSize) 232 }) 233 } 234 } 235 236 func BenchmarkMVCCInitPut_RocksDB(b *testing.B) { 237 ctx := context.Background() 238 for _, valueSize := range []int{10, 100, 1000, 10000} { 239 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 240 runMVCCInitPut(ctx, b, setupMVCCInMemRocksDB, valueSize) 241 }) 242 } 243 } 244 245 func BenchmarkMVCCBlindInitPut_RocksDB(b *testing.B) { 246 ctx := context.Background() 247 for _, valueSize := range []int{10, 100, 1000, 10000} { 248 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 249 runMVCCBlindInitPut(ctx, b, setupMVCCInMemRocksDB, valueSize) 250 }) 251 } 252 } 253 254 func BenchmarkMVCCPutDelete_RocksDB(b *testing.B) { 255 ctx := context.Background() 256 rocksdb := setupMVCCInMemRocksDB(b, "put_delete") 257 defer rocksdb.Close() 258 259 r := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 260 value := roachpb.MakeValueFromBytes(randutil.RandBytes(r, 10)) 261 var blockNum int64 262 263 for i := 0; i < b.N; i++ { 264 blockID := r.Int63() 265 blockNum++ 266 key := encoding.EncodeVarintAscending(nil, blockID) 267 key = encoding.EncodeVarintAscending(key, blockNum) 268 269 if err := MVCCPut(ctx, rocksdb, nil, key, hlc.Timestamp{}, value, nil /* txn */); err != nil { 270 b.Fatal(err) 271 } 272 if err := MVCCDelete(ctx, rocksdb, nil, key, hlc.Timestamp{}, nil /* txn */); err != nil { 273 b.Fatal(err) 274 } 275 } 276 } 277 278 func BenchmarkMVCCBatchPut_RocksDB(b *testing.B) { 279 ctx := context.Background() 280 for _, valueSize := range []int{10} { 281 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 282 for _, batchSize := range []int{1, 100, 10000, 100000} { 283 b.Run(fmt.Sprintf("batchSize=%d", batchSize), func(b *testing.B) { 284 runMVCCBatchPut(ctx, b, setupMVCCInMemRocksDB, valueSize, batchSize) 285 }) 286 } 287 }) 288 } 289 } 290 291 func BenchmarkMVCCBatchTimeSeries_RocksDB(b *testing.B) { 292 ctx := context.Background() 293 for _, batchSize := range []int{282} { 294 b.Run(fmt.Sprintf("batchSize=%d", batchSize), func(b *testing.B) { 295 runMVCCBatchTimeSeries(ctx, b, setupMVCCInMemRocksDB, batchSize) 296 }) 297 } 298 } 299 300 // BenchmarkMVCCMergeTimeSeries computes performance of merging time series 301 // data. Uses an in-memory engine. 302 func BenchmarkMVCCMergeTimeSeries_RocksDB(b *testing.B) { 303 ctx := context.Background() 304 ts := &roachpb.InternalTimeSeriesData{ 305 StartTimestampNanos: 0, 306 SampleDurationNanos: 1000, 307 Samples: []roachpb.InternalTimeSeriesSample{ 308 {Offset: 0, Count: 1, Sum: 5.0}, 309 }, 310 } 311 var value roachpb.Value 312 if err := value.SetProto(ts); err != nil { 313 b.Fatal(err) 314 } 315 runMVCCMerge(ctx, b, setupMVCCInMemRocksDB, &value, 1024) 316 } 317 318 // BenchmarkMVCCGetMergedTimeSeries computes performance of reading merged 319 // time series data using `MVCCGet()`. Uses an in-memory engine. 320 func BenchmarkMVCCGetMergedTimeSeries_RocksDB(b *testing.B) { 321 if testing.Short() { 322 b.Skip("short flag") 323 } 324 ctx := context.Background() 325 for _, numKeys := range []int{1, 16, 256} { 326 b.Run(fmt.Sprintf("numKeys=%d", numKeys), func(b *testing.B) { 327 for _, mergesPerKey := range []int{1, 16, 256} { 328 b.Run(fmt.Sprintf("mergesPerKey=%d", mergesPerKey), func(b *testing.B) { 329 runMVCCGetMergedValue(ctx, b, setupMVCCInMemRocksDB, numKeys, mergesPerKey) 330 }) 331 } 332 }) 333 } 334 } 335 336 // DeleteRange benchmarks below (using on-disk data). 337 338 func BenchmarkMVCCDeleteRange_RocksDB(b *testing.B) { 339 if testing.Short() { 340 b.Skip("short flag") 341 } 342 ctx := context.Background() 343 for _, valueSize := range []int{8, 32, 256} { 344 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 345 runMVCCDeleteRange(ctx, b, setupMVCCRocksDB, valueSize) 346 }) 347 } 348 } 349 350 func BenchmarkClearRange_RocksDB(b *testing.B) { 351 if testing.Short() { 352 b.Skip("TODO: fix benchmark") 353 } 354 ctx := context.Background() 355 runClearRange(ctx, b, setupMVCCRocksDB, func(eng Engine, batch Batch, start, end MVCCKey) error { 356 return batch.ClearRange(start, end) 357 }) 358 } 359 360 func BenchmarkClearIterRange_RocksDB(b *testing.B) { 361 ctx := context.Background() 362 runClearRange(ctx, b, setupMVCCRocksDB, func(eng Engine, batch Batch, start, end MVCCKey) error { 363 iter := eng.NewIterator(IterOptions{UpperBound: roachpb.KeyMax}) 364 defer iter.Close() 365 return batch.ClearIterRange(iter, start.Key, end.Key) 366 }) 367 } 368 369 func BenchmarkMVCCGarbageCollect_RocksDB(b *testing.B) { 370 if testing.Short() { 371 b.Skip("short flag") 372 } 373 374 // NB: To debug #16068, test only 128-128-15000-6. 375 ctx := context.Background() 376 for _, keySize := range []int{128} { 377 b.Run(fmt.Sprintf("keySize=%d", keySize), func(b *testing.B) { 378 for _, valSize := range []int{128} { 379 b.Run(fmt.Sprintf("valSize=%d", valSize), func(b *testing.B) { 380 for _, numKeys := range []int{1, 1024} { 381 b.Run(fmt.Sprintf("numKeys=%d", numKeys), func(b *testing.B) { 382 for _, numVersions := range []int{2, 1024} { 383 b.Run(fmt.Sprintf("numVersions=%d", numVersions), func(b *testing.B) { 384 runMVCCGarbageCollect(ctx, b, setupMVCCInMemRocksDB, benchGarbageCollectOptions{ 385 benchDataOptions: benchDataOptions{ 386 numKeys: numKeys, 387 numVersions: numVersions, 388 valueBytes: valSize, 389 }, 390 keyBytes: keySize, 391 deleteVersions: numVersions - 1, 392 }) 393 }) 394 } 395 }) 396 } 397 }) 398 } 399 }) 400 } 401 } 402 403 func BenchmarkBatchApplyBatchRepr_RocksDB(b *testing.B) { 404 if testing.Short() { 405 b.Skip("short flag") 406 } 407 ctx := context.Background() 408 for _, indexed := range []bool{false, true} { 409 b.Run(fmt.Sprintf("indexed=%t", indexed), func(b *testing.B) { 410 for _, sequential := range []bool{false, true} { 411 b.Run(fmt.Sprintf("seq=%t", sequential), func(b *testing.B) { 412 for _, valueSize := range []int{10} { 413 b.Run(fmt.Sprintf("valueSize=%d", valueSize), func(b *testing.B) { 414 for _, batchSize := range []int{10000} { 415 b.Run(fmt.Sprintf("batchSize=%d", batchSize), func(b *testing.B) { 416 runBatchApplyBatchRepr(ctx, b, setupMVCCInMemRocksDB, 417 indexed, sequential, valueSize, batchSize) 418 }) 419 } 420 }) 421 } 422 }) 423 } 424 }) 425 } 426 } 427 428 func BenchmarkBatchBuilderPut(b *testing.B) { 429 value := make([]byte, 10) 430 for i := range value { 431 value[i] = byte(i) 432 } 433 keyBuf := append(make([]byte, 0, 64), []byte("key-")...) 434 435 b.ResetTimer() 436 437 const batchSize = 1000 438 batch := &RocksDBBatchBuilder{} 439 for i := 0; i < b.N; i += batchSize { 440 end := i + batchSize 441 if end > b.N { 442 end = b.N 443 } 444 445 for j := i; j < end; j++ { 446 key := roachpb.Key(encoding.EncodeUvarintAscending(keyBuf[:4], uint64(j))) 447 ts := hlc.Timestamp{WallTime: int64(j)} 448 batch.Put(MVCCKey{key, ts}, value) 449 } 450 batch.Finish() 451 } 452 453 b.StopTimer() 454 }