github.com/onflow/atree@v0.6.0/array_bench_test.go (about) 1 /* 2 * Atree - Scalable Arrays and Ordered Maps 3 * 4 * Copyright 2021 Dapper Labs, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package atree 20 21 import ( 22 "math/rand" 23 "testing" 24 25 "github.com/stretchr/testify/require" 26 ) 27 28 var noop Storable 29 30 func BenchmarkArrayGet100x(b *testing.B) { 31 benchmarks := []struct { 32 name string 33 initialArraySize int 34 numberOfOps int 35 long bool 36 }{ 37 {"10", 10, 100, false}, 38 {"1000", 1000, 100, false}, 39 {"10000", 10_000, 100, false}, 40 {"100000", 100_000, 100, false}, 41 {"1000000", 1_000_000, 100, false}, 42 {"10000000", 10_000_000, 100, true}, 43 } 44 for _, bm := range benchmarks { 45 b.Run(bm.name, func(b *testing.B) { 46 if bm.long && testing.Short() { 47 b.Skipf("Skipping %s in short mode", bm.name) 48 } 49 benchmarkArrayGet(b, bm.initialArraySize, bm.numberOfOps) 50 }) 51 } 52 } 53 54 func BenchmarkArrayInsert100x(b *testing.B) { 55 benchmarks := []struct { 56 name string 57 initialArraySize int 58 numberOfOps int 59 long bool 60 }{ 61 {"10", 10, 100, false}, 62 {"1000", 1000, 100, false}, 63 {"10000", 10_000, 100, false}, 64 {"100000", 100_000, 100, false}, 65 {"1000000", 1_000_000, 100, true}, 66 {"10000000", 10_000_000, 100, true}, 67 } 68 for _, bm := range benchmarks { 69 b.Run(bm.name, func(b *testing.B) { 70 if bm.long && testing.Short() { 71 b.Skipf("Skipping %s in short mode", bm.name) 72 } 73 benchmarkArrayInsert(b, bm.initialArraySize, bm.numberOfOps) 74 }) 75 } 76 } 77 78 func BenchmarkArrayRemove100x(b *testing.B) { 79 benchmarks := []struct { 80 name string 81 initialArraySize int 82 numberOfOps int 83 long bool 84 }{ 85 {"100", 100, 100, false}, 86 {"1000", 1000, 100, false}, 87 {"10000", 10_000, 100, false}, 88 {"100000", 100_000, 100, false}, 89 {"1000000", 1_000_000, 100, true}, 90 {"10000000", 10_000_000, 100, true}, 91 } 92 for _, bm := range benchmarks { 93 b.Run(bm.name, func(b *testing.B) { 94 if bm.long && testing.Short() { 95 b.Skipf("Skipping %s in short mode", bm.name) 96 } 97 benchmarkArrayRemove(b, bm.initialArraySize, bm.numberOfOps) 98 }) 99 } 100 } 101 102 // BenchmarkArrayRemoveAll benchmarks removing all elements in a loop. 103 func BenchmarkArrayRemoveAll(b *testing.B) { 104 benchmarks := []struct { 105 name string 106 initialArraySize int 107 long bool 108 }{ 109 {"100", 100, false}, 110 {"1000", 1000, false}, 111 {"10000", 10_000, false}, 112 {"100000", 100_000, false}, 113 } 114 for _, bm := range benchmarks { 115 b.Run(bm.name, func(b *testing.B) { 116 if bm.long && testing.Short() { 117 b.Skipf("Skipping %s in short mode", bm.name) 118 } 119 benchmarkArrayRemoveAll(b, bm.initialArraySize) 120 }) 121 } 122 } 123 124 // BenchmarkArrayPopIterate benchmarks removing all elements using PopIterate. 125 func BenchmarkArrayPopIterate(b *testing.B) { 126 benchmarks := []struct { 127 name string 128 initialArraySize int 129 long bool 130 }{ 131 {"100", 100, false}, 132 {"1000", 1000, false}, 133 {"10000", 10_000, false}, 134 {"100000", 100_000, false}, 135 } 136 for _, bm := range benchmarks { 137 b.Run(bm.name, func(b *testing.B) { 138 if bm.long && testing.Short() { 139 b.Skipf("Skipping %s in short mode", bm.name) 140 } 141 benchmarkArrayPopIterate(b, bm.initialArraySize) 142 }) 143 } 144 } 145 146 func BenchmarkNewArrayFromAppend(b *testing.B) { 147 benchmarks := []struct { 148 name string 149 initialArraySize int 150 long bool 151 }{ 152 {"100", 100, false}, 153 {"1000", 1000, false}, 154 {"10000", 10_000, false}, 155 {"100000", 100_000, false}, 156 } 157 for _, bm := range benchmarks { 158 b.Run(bm.name, func(b *testing.B) { 159 if bm.long && testing.Short() { 160 b.Skipf("Skipping %s in short mode", bm.name) 161 } 162 benchmarkNewArrayFromAppend(b, bm.initialArraySize) 163 }) 164 } 165 } 166 167 func BenchmarkNewArrayFromBatchData(b *testing.B) { 168 benchmarks := []struct { 169 name string 170 initialArraySize int 171 long bool 172 }{ 173 {"100", 100, false}, 174 {"1000", 1000, false}, 175 {"10000", 10_000, false}, 176 {"100000", 100_000, false}, 177 } 178 for _, bm := range benchmarks { 179 b.Run(bm.name, func(b *testing.B) { 180 if bm.long && testing.Short() { 181 b.Skipf("Skipping %s in short mode", bm.name) 182 } 183 benchmarkNewArrayFromBatchData(b, bm.initialArraySize) 184 }) 185 } 186 } 187 188 func setupArray(b *testing.B, r *rand.Rand, storage *PersistentSlabStorage, initialArraySize int) *Array { 189 190 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 191 192 typeInfo := testTypeInfo{42} 193 194 array, err := NewArray(storage, address, typeInfo) 195 require.NoError(b, err) 196 197 for i := 0; i < initialArraySize; i++ { 198 v := RandomValue(r) 199 err := array.Append(v) 200 require.NoError(b, err) 201 } 202 203 err = storage.Commit() 204 require.NoError(b, err) 205 206 arrayID := array.StorageID() 207 208 storage.DropCache() 209 210 newArray, err := NewArrayWithRootID(storage, arrayID) 211 require.NoError(b, err) 212 213 return newArray 214 } 215 216 func benchmarkArrayGet(b *testing.B, initialArraySize, numberOfOps int) { 217 218 b.StopTimer() 219 220 r := newRand(b) 221 222 storage := newTestPersistentStorage(b) 223 224 array := setupArray(b, r, storage, initialArraySize) 225 226 var storable Storable 227 228 b.StartTimer() 229 230 for i := 0; i < b.N; i++ { 231 for i := 0; i < numberOfOps; i++ { 232 index := r.Intn(int(array.Count())) 233 storable, _ = array.Get(uint64(index)) 234 } 235 } 236 237 noop = storable 238 } 239 240 func benchmarkArrayInsert(b *testing.B, initialArraySize, numberOfOps int) { 241 242 b.StopTimer() 243 244 r := newRand(b) 245 246 storage := newTestPersistentStorage(b) 247 248 for i := 0; i < b.N; i++ { 249 250 b.StopTimer() 251 252 array := setupArray(b, r, storage, initialArraySize) 253 254 b.StartTimer() 255 256 for i := 0; i < numberOfOps; i++ { 257 index := r.Intn(int(array.Count())) 258 v := RandomValue(r) 259 _ = array.Insert(uint64(index), v) 260 } 261 } 262 } 263 264 func benchmarkArrayRemove(b *testing.B, initialArraySize, numberOfOps int) { 265 266 b.StopTimer() 267 268 r := newRand(b) 269 270 storage := newTestPersistentStorage(b) 271 272 for i := 0; i < b.N; i++ { 273 274 b.StopTimer() 275 276 array := setupArray(b, r, storage, initialArraySize) 277 278 b.StartTimer() 279 280 for i := 0; i < numberOfOps; i++ { 281 index := r.Intn(int(array.Count())) 282 _, _ = array.Remove(uint64(index)) 283 } 284 } 285 } 286 287 func benchmarkArrayRemoveAll(b *testing.B, initialArraySize int) { 288 289 b.StopTimer() 290 291 r := newRand(b) 292 293 storage := newTestPersistentStorage(b) 294 295 var storable Storable 296 297 for i := 0; i < b.N; i++ { 298 299 b.StopTimer() 300 301 array := setupArray(b, r, storage, initialArraySize) 302 303 b.StartTimer() 304 305 for i := initialArraySize - 1; i >= 0; i-- { 306 storable, _ = array.Remove(uint64(i)) 307 } 308 } 309 310 noop = storable 311 } 312 313 func benchmarkArrayPopIterate(b *testing.B, initialArraySize int) { 314 315 b.StopTimer() 316 317 r := newRand(b) 318 319 storage := newTestPersistentStorage(b) 320 321 var storable Storable 322 323 for i := 0; i < b.N; i++ { 324 325 b.StopTimer() 326 327 array := setupArray(b, r, storage, initialArraySize) 328 329 b.StartTimer() 330 331 err := array.PopIterate(func(s Storable) { 332 storable = s 333 }) 334 if err != nil { 335 b.Errorf(err.Error()) 336 } 337 } 338 339 noop = storable 340 } 341 342 func benchmarkNewArrayFromAppend(b *testing.B, initialArraySize int) { 343 344 b.StopTimer() 345 346 r := newRand(b) 347 348 storage := newTestPersistentStorage(b) 349 350 array := setupArray(b, r, storage, initialArraySize) 351 352 b.StartTimer() 353 354 for i := 0; i < b.N; i++ { 355 copied, _ := NewArray(storage, array.Address(), array.Type()) 356 357 _ = array.Iterate(func(value Value) (bool, error) { 358 _ = copied.Append(value) 359 return true, nil 360 }) 361 362 if copied.Count() != array.Count() { 363 b.Errorf("Copied array has %d elements, want %d", copied.Count(), array.Count()) 364 } 365 } 366 } 367 368 func benchmarkNewArrayFromBatchData(b *testing.B, initialArraySize int) { 369 370 b.StopTimer() 371 372 r := newRand(b) 373 374 storage := newTestPersistentStorage(b) 375 376 array := setupArray(b, r, storage, initialArraySize) 377 378 b.StartTimer() 379 380 for i := 0; i < b.N; i++ { 381 iter, err := array.Iterator() 382 require.NoError(b, err) 383 384 copied, _ := NewArrayFromBatchData(storage, array.Address(), array.Type(), func() (Value, error) { 385 return iter.Next() 386 }) 387 388 if copied.Count() != array.Count() { 389 b.Errorf("Copied array has %d elements, want %d", copied.Count(), array.Count()) 390 } 391 } 392 }