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 }