github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/prolly/benchmark/utils_test.go (about)

     1  // Copyright 2022 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  	"math/rand"
    20  	"os"
    21  	"path/filepath"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/require"
    25  	"go.etcd.io/bbolt"
    26  
    27  	"github.com/dolthub/dolt/go/store/chunks"
    28  	"github.com/dolthub/dolt/go/store/pool"
    29  	"github.com/dolthub/dolt/go/store/prolly"
    30  	"github.com/dolthub/dolt/go/store/prolly/tree"
    31  	"github.com/dolthub/dolt/go/store/types"
    32  	"github.com/dolthub/dolt/go/store/val"
    33  )
    34  
    35  type prollyBench struct {
    36  	m    prolly.Map
    37  	tups [][2]val.Tuple
    38  }
    39  
    40  type typesBench struct {
    41  	m    types.Map
    42  	tups [][2]types.Tuple
    43  }
    44  
    45  type bboltBench struct {
    46  	db   *bbolt.DB
    47  	tups [][2]val.Tuple
    48  }
    49  
    50  func generateProllyBench(b *testing.B, size uint64) prollyBench {
    51  	b.StopTimer()
    52  	defer b.StartTimer()
    53  	ctx := context.Background()
    54  	ns := newTestNodeStore()
    55  
    56  	kd := val.NewTupleDescriptor(
    57  		val.Type{Enc: val.Uint64Enc, Nullable: false},
    58  	)
    59  	vd := val.NewTupleDescriptor(
    60  		val.Type{Enc: val.Int64Enc, Nullable: true},
    61  		val.Type{Enc: val.Int64Enc, Nullable: true},
    62  		val.Type{Enc: val.Int64Enc, Nullable: true},
    63  		val.Type{Enc: val.Int64Enc, Nullable: true},
    64  		val.Type{Enc: val.Int64Enc, Nullable: true},
    65  	)
    66  
    67  	tups := generateProllyTuples(kd, vd, size)
    68  
    69  	tt := make([]val.Tuple, 0, len(tups)*2)
    70  	for i := range tups {
    71  		tt = append(tt, tups[i][0], tups[i][1])
    72  	}
    73  
    74  	m, err := prolly.NewMapFromTuples(ctx, ns, kd, vd, tt...)
    75  	if err != nil {
    76  		panic(err)
    77  	}
    78  
    79  	return prollyBench{m: m, tups: tups}
    80  }
    81  
    82  var shared = pool.NewBuffPool()
    83  
    84  func newTestNodeStore() tree.NodeStore {
    85  	ts := &chunks.TestStorage{}
    86  	return tree.NewNodeStore(ts.NewView())
    87  }
    88  
    89  func generateProllyTuples(kd, vd val.TupleDesc, size uint64) [][2]val.Tuple {
    90  	src := rand.NewSource(0)
    91  
    92  	tups := make([][2]val.Tuple, size)
    93  	kb := val.NewTupleBuilder(kd)
    94  	vb := val.NewTupleBuilder(vd)
    95  
    96  	for i := range tups {
    97  		// key
    98  		kb.PutUint64(0, uint64(i))
    99  		tups[i][0] = kb.Build(shared)
   100  
   101  		// val
   102  		vb.PutInt64(0, src.Int63())
   103  		vb.PutInt64(1, src.Int63())
   104  		vb.PutInt64(2, src.Int63())
   105  		vb.PutInt64(3, src.Int63())
   106  		vb.PutInt64(4, src.Int63())
   107  		tups[i][1] = vb.Build(shared)
   108  	}
   109  
   110  	return tups
   111  }
   112  
   113  func generateTypesBench(b *testing.B, size uint64) typesBench {
   114  	b.StopTimer()
   115  	defer b.StartTimer()
   116  	ctx := context.Background()
   117  	tups := generateTypesTuples(size)
   118  
   119  	tt := make([]types.Value, len(tups)*2)
   120  	for i := range tups {
   121  		tt[i*2] = tups[i][0]
   122  		tt[(i*2)+1] = tups[i][1]
   123  	}
   124  
   125  	m, err := types.NewMap(ctx, newTestVRW(), tt...)
   126  	if err != nil {
   127  		panic(err)
   128  	}
   129  
   130  	return typesBench{m: m, tups: tups}
   131  }
   132  
   133  func newTestVRW() types.ValueReadWriter {
   134  	ts := &chunks.TestStorage{}
   135  	return types.NewValueStore(ts.NewView())
   136  }
   137  
   138  func generateTypesTuples(size uint64) [][2]types.Tuple {
   139  	src := rand.NewSource(0)
   140  
   141  	// tags
   142  	t0, t1, t2 := types.Uint(0), types.Uint(1), types.Uint(2)
   143  	t3, t4, t5 := types.Uint(3), types.Uint(4), types.Uint(5)
   144  
   145  	tups := make([][2]types.Tuple, size)
   146  	for i := range tups {
   147  
   148  		// key
   149  		k := types.Int(i)
   150  		tups[i][0], _ = types.NewTuple(types.Format_Default, t0, k)
   151  
   152  		// val
   153  		var vv [5 * 2]types.Value
   154  		for i := 1; i < 10; i += 2 {
   155  			vv[i] = types.Uint(uint64(src.Int63()))
   156  		}
   157  		vv[0], vv[2], vv[4], vv[6], vv[8] = t1, t2, t3, t4, t5
   158  
   159  		tups[i][1], _ = types.NewTuple(types.Format_Default, vv[:]...)
   160  	}
   161  
   162  	return tups
   163  }
   164  
   165  func generateBBoltBench(b *testing.B, size uint64) bboltBench {
   166  	b.StopTimer()
   167  	defer b.StartTimer()
   168  	kd := val.NewTupleDescriptor(
   169  		val.Type{Enc: val.Uint64Enc, Nullable: false},
   170  	)
   171  	vd := val.NewTupleDescriptor(
   172  		val.Type{Enc: val.Int64Enc, Nullable: true},
   173  		val.Type{Enc: val.Int64Enc, Nullable: true},
   174  		val.Type{Enc: val.Int64Enc, Nullable: true},
   175  		val.Type{Enc: val.Int64Enc, Nullable: true},
   176  		val.Type{Enc: val.Int64Enc, Nullable: true},
   177  	)
   178  
   179  	path, err := os.MkdirTemp("", "*")
   180  	require.NoError(b, err)
   181  	path = filepath.Join(path, "bolt.db")
   182  
   183  	db, err := bbolt.Open(path, 0666, &bbolt.Options{
   184  		// turn off fsync
   185  		NoGrowSync:     true,
   186  		NoFreelistSync: true,
   187  		NoSync:         true,
   188  	})
   189  	require.NoError(b, err)
   190  
   191  	err = db.Update(func(tx *bbolt.Tx) error {
   192  		_, err = tx.CreateBucket(bucket)
   193  		return err
   194  	})
   195  	require.NoError(b, err)
   196  
   197  	tups := generateProllyTuples(kd, vd, size)
   198  
   199  	const batch = 4096
   200  	for i := 0; i < len(tups); i += batch {
   201  		err = db.Update(func(tx *bbolt.Tx) error {
   202  			bck := tx.Bucket(bucket)
   203  			for j := i; j < (i+batch) && j < len(tups); j++ {
   204  				require.NoError(b, bck.Put(tups[j][0], tups[j][1]))
   205  			}
   206  			return nil
   207  		})
   208  		require.NoError(b, err)
   209  	}
   210  	return bboltBench{db: db, tups: tups}
   211  }