github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/nbs/benchmarks/main.go (about) 1 // Copyright 2019 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 // This file incorporates work covered by the following copyright and 16 // permission notice: 17 // 18 // Copyright 2016 Attic Labs, Inc. All rights reserved. 19 // Licensed under the Apache License, version 2.0: 20 // http://www.apache.org/licenses/LICENSE-2.0 21 22 package main 23 24 import ( 25 "context" 26 "fmt" 27 "io/ioutil" 28 "os" 29 "regexp" 30 "sort" 31 "time" 32 33 "github.com/aws/aws-sdk-go/aws" 34 "github.com/aws/aws-sdk-go/aws/session" 35 "github.com/aws/aws-sdk-go/service/dynamodb" 36 "github.com/aws/aws-sdk-go/service/s3" 37 "github.com/dustin/go-humanize" 38 flag "github.com/juju/gnuflag" 39 "github.com/stretchr/testify/assert" 40 41 "github.com/dolthub/dolt/go/store/chunks" 42 "github.com/dolthub/dolt/go/store/d" 43 "github.com/dolthub/dolt/go/store/nbs" 44 "github.com/dolthub/dolt/go/store/types" 45 "github.com/dolthub/dolt/go/store/util/profile" 46 ) 47 48 var ( 49 count = flag.Int("c", 10, "Number of iterations to run") 50 dataSize = flag.Uint64("data", 4096, "MiB of data to test with") 51 mtMiB = flag.Uint64("mem", 64, "Size in MiB of memTable") 52 useNBS = flag.String("useNBS", "", "Existing Database to use for not-WriteNovel benchmarks") 53 toNBS = flag.String("toNBS", "", "Write to an NBS store in the given directory") 54 useAWS = flag.String("useAWS", "", "Name of existing Database to use for not-WriteNovel benchmarks") 55 toAWS = flag.String("toAWS", "", "Write to an NBS store in AWS") 56 toFile = flag.String("toFile", "", "Write to a file in the given directory") 57 ) 58 59 const s3Bucket = "attic-nbs" 60 const dynamoTable = "attic-nbs" 61 62 type panickingBencher struct { 63 n int 64 } 65 66 func (pb panickingBencher) Errorf(format string, args ...interface{}) { 67 panic(fmt.Sprintf(format, args...)) 68 } 69 70 func (pb panickingBencher) N() int { 71 return pb.n 72 } 73 74 func (pb panickingBencher) ResetTimer() {} 75 func (pb panickingBencher) StartTimer() {} 76 func (pb panickingBencher) StopTimer() {} 77 78 func main() { 79 profile.RegisterProfileFlags(flag.CommandLine) 80 flag.Parse(true) 81 82 if flag.NArg() < 1 { 83 flag.Usage() 84 os.Exit(1) 85 } 86 87 pb := panickingBencher{*count} 88 89 src, err := getInput((*dataSize) * humanize.MiByte) 90 d.PanicIfError(err) 91 defer func() { 92 err := src.Close() 93 d.PanicIfError(err) 94 }() 95 96 bufSize := (*mtMiB) * humanize.MiByte 97 98 open := newNullBlockStore 99 wrote := false 100 var writeDB func() 101 var refresh func() (chunks.ChunkStore, error) 102 if *toNBS != "" || *toFile != "" || *toAWS != "" { 103 var reset func() 104 if *toNBS != "" { 105 dir := makeTempDir(*toNBS, pb) 106 defer func() { 107 err := os.RemoveAll(dir) 108 d.PanicIfError(err) 109 }() 110 open = func() (chunks.ChunkStore, error) { 111 return nbs.NewLocalStore(context.Background(), types.Format_Default.VersionString(), dir, bufSize) 112 } 113 reset = func() { 114 err := os.RemoveAll(dir) 115 d.PanicIfError(err) 116 err = os.MkdirAll(dir, 0777) 117 d.PanicIfError(err) 118 } 119 120 } else if *toFile != "" { 121 dir := makeTempDir(*toFile, pb) 122 defer func() { 123 err := os.RemoveAll(dir) 124 d.PanicIfError(err) 125 }() 126 open = func() (chunks.ChunkStore, error) { 127 f, err := ioutil.TempFile(dir, "") 128 d.Chk.NoError(err) 129 return newFileBlockStore(f) 130 } 131 reset = func() { 132 err := os.RemoveAll(dir) 133 d.PanicIfError(err) 134 err = os.MkdirAll(dir, 0777) 135 d.PanicIfError(err) 136 } 137 138 } else if *toAWS != "" { 139 sess := session.Must(session.NewSession(aws.NewConfig().WithRegion("us-west-2"))) 140 open = func() (chunks.ChunkStore, error) { 141 return nbs.NewAWSStore(context.Background(), types.Format_Default.VersionString(), dynamoTable, *toAWS, s3Bucket, s3.New(sess), dynamodb.New(sess), bufSize) 142 } 143 reset = func() { 144 ddb := dynamodb.New(sess) 145 _, err := ddb.DeleteItem(&dynamodb.DeleteItemInput{ 146 TableName: aws.String(dynamoTable), 147 Key: map[string]*dynamodb.AttributeValue{ 148 "db": {S: toAWS}, 149 }, 150 }) 151 d.PanicIfError(err) 152 } 153 } 154 155 writeDB = func() { wrote = ensureNovelWrite(wrote, open, src, pb) } 156 refresh = func() (chunks.ChunkStore, error) { 157 reset() 158 return open() 159 } 160 } else { 161 if *useNBS != "" { 162 open = func() (chunks.ChunkStore, error) { 163 return nbs.NewLocalStore(context.Background(), types.Format_Default.VersionString(), *useNBS, bufSize) 164 } 165 } else if *useAWS != "" { 166 sess := session.Must(session.NewSession(aws.NewConfig().WithRegion("us-west-2"))) 167 open = func() (chunks.ChunkStore, error) { 168 return nbs.NewAWSStore(context.Background(), types.Format_Default.VersionString(), dynamoTable, *useAWS, s3Bucket, s3.New(sess), dynamodb.New(sess), bufSize) 169 } 170 } 171 writeDB = func() {} 172 refresh = func() (chunks.ChunkStore, error) { panic("WriteNovel unsupported with --useLDB and --useNBS") } 173 } 174 175 benchmarks := []struct { 176 name string 177 setup func() 178 run func() 179 }{ 180 {"WriteNovel", func() {}, func() { wrote = benchmarkNovelWrite(refresh, src, pb) }}, 181 {"WriteDuplicate", writeDB, func() { benchmarkNoRefreshWrite(open, src, pb) }}, 182 {"ReadSequential", writeDB, func() { 183 benchmarkRead(open, src.GetHashes(), src, pb) 184 }}, 185 {"ReadHashOrder", writeDB, func() { 186 ordered := src.GetHashes() 187 sort.Sort(ordered) 188 benchmarkRead(open, ordered, src, pb) 189 }}, 190 {"ReadManySequential", writeDB, func() { benchmarkReadMany(open, src.GetHashes(), src, 1<<8, 6, pb) }}, 191 {"ReadManyHashOrder", writeDB, func() { 192 ordered := src.GetHashes() 193 sort.Sort(ordered) 194 benchmarkReadMany(open, ordered, src, 1<<8, 6, pb) 195 }}, 196 } 197 w := 0 198 for _, bm := range benchmarks { 199 if len(bm.name) > w { 200 w = len(bm.name) 201 } 202 } 203 defer profile.MaybeStartProfile().Stop() 204 for _, bm := range benchmarks { 205 if matched, _ := regexp.MatchString(flag.Arg(0), bm.name); matched { 206 trialName := fmt.Sprintf("%dMiB/%sbuffer/%-[3]*s", *dataSize, humanize.IBytes(bufSize), w, bm.name) 207 bm.setup() 208 dur := time.Duration(0) 209 var trials []time.Duration 210 for i := 0; i < *count; i++ { 211 d.Chk.NoError(dropCache()) 212 src.PrimeFilesystemCache() 213 214 t := time.Now() 215 bm.run() 216 trialDur := time.Since(t) 217 trials = append(trials, trialDur) 218 dur += trialDur 219 } 220 fmt.Printf("%s\t%d\t%ss/iter %v\n", trialName, *count, humanize.FormatFloat("", (dur/time.Duration(*count)).Seconds()), formatTrials(trials)) 221 } 222 } 223 } 224 225 func makeTempDir(tmpdir string, t assert.TestingT) (dir string) { 226 dir, err := ioutil.TempDir(tmpdir, "") 227 assert.NoError(t, err) 228 return 229 } 230 231 func formatTrials(trials []time.Duration) (formatted []string) { 232 for _, trial := range trials { 233 formatted = append(formatted, humanize.FormatFloat("", trial.Seconds())) 234 } 235 return 236 }