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  }