github.com/onflow/atree@v0.6.0/basicarray_benchmark_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  	"testing"
    23  	"time"
    24  
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  // GENERAL COMMENT:
    29  // running this test with
    30  //
    31  //	go test -bench=.  -benchmem
    32  //
    33  // will track the heap allocations for the Benchmarks
    34  func BenchmarkXSBasicArray(b *testing.B) { benchmarkBasicArray(b, 10, 100) }
    35  
    36  func BenchmarkSBasicArray(b *testing.B) { benchmarkBasicArray(b, 1000, 100) }
    37  
    38  func BenchmarkMBasicArray(b *testing.B) { benchmarkBasicArray(b, 10_000, 100) }
    39  
    40  func BenchmarkLBasicArray(b *testing.B) { benchmarkBasicArray(b, 100_000, 100) }
    41  
    42  func BenchmarkXLBasicArray(b *testing.B) { benchmarkBasicArray(b, 1_000_000, 100) }
    43  
    44  func BenchmarkXXLBasicArray(b *testing.B) {
    45  	if testing.Short() {
    46  		b.Skip("Skipping BenchmarkXXLArray in short mode")
    47  	}
    48  	benchmarkBasicArray(b, 10_000_000, 100)
    49  }
    50  
    51  func BenchmarkXXXLBasicArray(b *testing.B) {
    52  	if testing.Short() {
    53  		b.Skip("Skipping BenchmarkXXXLArray in short mode")
    54  	}
    55  	benchmarkBasicArray(b, 100_000_000, 100)
    56  }
    57  
    58  // BenchmarkBasicArray benchmarks the performance of basic array
    59  func benchmarkBasicArray(b *testing.B, initialArraySize, numberOfElements int) {
    60  
    61  	r := newRand(b)
    62  
    63  	storage := newTestPersistentStorage(b)
    64  
    65  	address := Address{1, 2, 3, 4, 5, 6, 7, 8}
    66  
    67  	array, err := NewBasicArray(storage, address)
    68  	require.NoError(b, err)
    69  
    70  	// TODO capture arrayID here ?
    71  
    72  	var start time.Time
    73  	var totalRawDataSize uint32
    74  	var totalAppendTime time.Duration
    75  	var totalRemoveTime time.Duration
    76  	var totalInsertTime time.Duration
    77  	var totalLookupTime time.Duration
    78  
    79  	// setup
    80  	for i := 0; i < initialArraySize; i++ {
    81  		v := RandomValue(r)
    82  		storable, err := v.Storable(storage, array.Address(), MaxInlineArrayElementSize)
    83  		require.NoError(b, err)
    84  		totalRawDataSize += storable.ByteSize()
    85  		err = array.Append(v)
    86  		require.NoError(b, err)
    87  	}
    88  	require.NoError(b, storage.Commit())
    89  	b.ResetTimer()
    90  
    91  	arrayID := array.StorageID()
    92  
    93  	// append
    94  	storage.DropCache()
    95  	array, err = NewBasicArrayWithRootID(storage, arrayID)
    96  	require.NoError(b, err)
    97  
    98  	start = time.Now()
    99  	for i := 0; i < numberOfElements; i++ {
   100  		v := RandomValue(r)
   101  		storable, err := v.Storable(storage, array.Address(), MaxInlineArrayElementSize)
   102  		require.NoError(b, err)
   103  		totalRawDataSize += storable.ByteSize()
   104  		err = array.Append(v)
   105  		require.NoError(b, err)
   106  	}
   107  	require.NoError(b, storage.Commit())
   108  	totalAppendTime = time.Since(start)
   109  
   110  	// remove
   111  	storage.DropCache()
   112  	array, err = NewBasicArrayWithRootID(storage, arrayID)
   113  	require.NoError(b, err)
   114  
   115  	start = time.Now()
   116  	for i := 0; i < numberOfElements; i++ {
   117  		ind := r.Intn(int(array.Count()))
   118  		s, err := array.Remove(uint64(ind))
   119  		require.NoError(b, err)
   120  		storable, err := s.Storable(storage, array.Address(), MaxInlineArrayElementSize)
   121  		require.NoError(b, err)
   122  		totalRawDataSize -= storable.ByteSize()
   123  	}
   124  	require.NoError(b, storage.Commit())
   125  	totalRemoveTime = time.Since(start)
   126  
   127  	// insert
   128  	storage.DropCache()
   129  	array, err = NewBasicArrayWithRootID(storage, arrayID)
   130  	require.NoError(b, err)
   131  
   132  	start = time.Now()
   133  	for i := 0; i < numberOfElements; i++ {
   134  		ind := r.Intn(int(array.Count()))
   135  		v := RandomValue(r)
   136  		storable, err := v.Storable(storage, array.Address(), MaxInlineArrayElementSize)
   137  		require.NoError(b, err)
   138  		totalRawDataSize += storable.ByteSize()
   139  		err = array.Insert(uint64(ind), v)
   140  		require.NoError(b, err)
   141  	}
   142  	require.NoError(b, storage.Commit())
   143  	totalInsertTime = time.Since(start)
   144  
   145  	// lookup
   146  	storage.DropCache()
   147  	array, err = NewBasicArrayWithRootID(storage, arrayID)
   148  	require.NoError(b, err)
   149  
   150  	start = time.Now()
   151  	for i := 0; i < numberOfElements; i++ {
   152  		ind := r.Intn(int(array.Count()))
   153  		_, err := array.Get(uint64(ind))
   154  		require.NoError(b, err)
   155  	}
   156  	require.NoError(b, storage.Commit())
   157  	totalLookupTime = time.Since(start)
   158  
   159  	// random lookup
   160  	storage.baseStorage.ResetReporter()
   161  	storage.DropCache()
   162  	array, err = NewBasicArrayWithRootID(storage, arrayID)
   163  	require.NoError(b, err)
   164  
   165  	ind := r.Intn(int(array.Count()))
   166  	_, err = array.Get(uint64(ind))
   167  	require.NoError(b, err)
   168  	storageOverheadRatio := float64(storage.baseStorage.Size()) / float64(totalRawDataSize)
   169  	b.ReportMetric(float64(storage.baseStorage.SegmentsTouched()), "segments_touched")
   170  	b.ReportMetric(float64(storage.baseStorage.SegmentCounts()), "segments_total")
   171  	b.ReportMetric(float64(totalRawDataSize), "storage_raw_data_size")
   172  	b.ReportMetric(float64(storage.baseStorage.Size()), "storage_stored_data_size")
   173  	b.ReportMetric(float64(storage.baseStorage.BytesRetrieved()), "storage_bytes_loaded_for_lookup")
   174  	b.ReportMetric(storageOverheadRatio, "storage_overhead_ratio")
   175  	b.ReportMetric(float64(array.Count()), "number_of_elements")
   176  	b.ReportMetric(float64(int(totalAppendTime)), "append_100_time_(ns)")
   177  	b.ReportMetric(float64(int(totalRemoveTime)), "remove_100_time_(ns)")
   178  	b.ReportMetric(float64(int(totalInsertTime)), "insert_100_time_(ns)")
   179  	b.ReportMetric(float64(int(totalLookupTime)), "lookup_100_time_(ns)")
   180  	// b.ReportMetric(float64(storage.BytesRetrieved()), "bytes_retrieved")
   181  	// b.ReportMetric(float64(storage.BytesStored()), "bytes_stored")
   182  	// b.ReportMetric(float64(storage.SegmentTouched()), "segments_touched"
   183  }