github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/performance/serverbench/bench_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 serverbench 16 17 import ( 18 "context" 19 "fmt" 20 "os" 21 "path" 22 "runtime" 23 "runtime/pprof" 24 "strings" 25 "testing" 26 27 "github.com/gocraft/dbr/v2" 28 "golang.org/x/sync/errgroup" 29 30 srv "github.com/dolthub/dolt/go/cmd/dolt/commands/sqlserver" 31 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 32 "github.com/dolthub/dolt/go/libraries/doltcore/env" 33 "github.com/dolthub/dolt/go/libraries/utils/filesys" 34 "github.com/dolthub/dolt/go/store/types" 35 ) 36 37 type query string 38 39 type serverTest struct { 40 name string 41 setup []query 42 bench []query 43 } 44 45 // usage: `go test -bench .` 46 func BenchmarkServerExample(b *testing.B) { 47 48 setup := make([]query, 101) 49 setup[0] = "CREATE TABLE bench (pk int PRIMARY KEY AUTO_INCREMENT, c0 int);" 50 51 q := strings.Builder{} 52 q.WriteString("INSERT INTO bench (c0) VALUES (0)") 53 i := 1 54 for i < 1000 { 55 q.WriteString(fmt.Sprintf(",(%d)", i)) 56 i++ 57 } 58 qs := q.String() 59 60 for i := range setup { 61 if i == 0 { 62 continue 63 } 64 setup[i] = query(qs) 65 } 66 67 benchmarkServer(b, serverTest{ 68 name: "smoke bench", 69 setup: setup, 70 bench: []query{ 71 "SELECT count(*) FROM bench;", 72 }, 73 }) 74 } 75 76 func benchmarkServer(b *testing.B, test serverTest) { 77 var dEnv *env.DoltEnv 78 var cfg srv.ServerConfig 79 ctx := context.Background() 80 81 // setup 82 dEnv, cfg = getEnvAndConfig(ctx, b) 83 executeServerQueries(ctx, b, dEnv, cfg, test.setup) 84 85 // bench 86 f := getProfFile(b) 87 err := pprof.StartCPUProfile(f) 88 if err != nil { 89 b.Fatal(err) 90 } 91 defer func() { 92 pprof.StopCPUProfile() 93 if err = f.Close(); err != nil { 94 b.Fatal(err) 95 } 96 fmt.Printf("\twriting CPU profile for %s: %s\n", b.Name(), f.Name()) 97 }() 98 99 b.Run(test.name, func(b *testing.B) { 100 executeServerQueries(ctx, b, dEnv, cfg, test.bench) 101 }) 102 } 103 104 const ( 105 database = "dolt_bench" 106 port = 1234 107 108 name = "name" 109 email = "name@fake.horse" 110 ) 111 112 func getEnvAndConfig(ctx context.Context, b *testing.B) (dEnv *env.DoltEnv, cfg srv.ServerConfig) { 113 tmp := b.TempDir() 114 //b.Logf("db directory: %s", tmp) 115 dbDir := path.Join(tmp, database) 116 err := os.Mkdir(dbDir, os.ModePerm) 117 if err != nil { 118 b.Fatal(err) 119 } 120 121 err = os.Chdir(dbDir) 122 if err != nil { 123 b.Fatal(err) 124 } 125 126 fs, err := filesys.LocalFilesysWithWorkingDir(".") 127 if err != nil { 128 b.Fatal(err) 129 } 130 131 dEnv = env.Load(ctx, os.UserHomeDir, fs, doltdb.LocalDirDoltDB, "bench") 132 err = dEnv.InitRepo(ctx, types.Format_7_18, name, email) 133 if err != nil { 134 b.Fatal(err) 135 } 136 137 yaml := []byte(fmt.Sprintf(` 138 log_level: warning 139 140 behavior: 141 read_only: false 142 143 user: 144 name: "root" 145 password: "" 146 147 databases: 148 - name: "%s" 149 path: "%s" 150 151 listener: 152 host: localhost 153 port: %d 154 max_connections: 128 155 read_timeout_millis: 28800000 156 write_timeout_millis: 28800000 157 `, database, dbDir, port)) 158 159 cfg, err = srv.NewYamlConfig(yaml) 160 if err != nil { 161 b.Fatal(err) 162 } 163 164 return dEnv, cfg 165 } 166 167 func getProfFile(b *testing.B) *os.File { 168 _, testFile, _, _ := runtime.Caller(0) 169 170 f, err := os.Create(path.Join(path.Dir(testFile), b.Name()+".out")) 171 if err != nil { 172 b.Fatal(err) 173 } 174 return f 175 } 176 177 func executeServerQueries(ctx context.Context, b *testing.B, dEnv *env.DoltEnv, cfg srv.ServerConfig, queries []query) { 178 serverController := srv.CreateServerController() 179 180 eg, ctx := errgroup.WithContext(ctx) 181 182 //b.Logf("Starting server with Config %v\n", srv.ConfigInfo(cfg)) 183 eg.Go(func() (err error) { 184 startErr, closeErr := srv.Serve(ctx, "", cfg, serverController, dEnv) 185 if startErr != nil { 186 return startErr 187 } 188 if closeErr != nil { 189 return closeErr 190 } 191 return nil 192 }) 193 if err := serverController.WaitForStart(); err != nil { 194 b.Fatal(err) 195 } 196 197 for _, q := range queries { 198 if err := executeQuery(cfg, q); err != nil { 199 b.Fatal(err) 200 } 201 } 202 203 serverController.StopServer() 204 if err := serverController.WaitForClose(); err != nil { 205 b.Fatal(err) 206 } 207 if err := eg.Wait(); err != nil { 208 b.Fatal(err) 209 } 210 } 211 212 func executeQuery(cfg srv.ServerConfig, q query) error { 213 cs := srv.ConnectionString(cfg) + database 214 conn, err := dbr.Open("mysql", cs, nil) 215 if err != nil { 216 return err 217 } 218 219 rows, err := conn.Query(string(q)) 220 if err != nil { 221 return err 222 } 223 224 for { 225 if err = rows.Err(); err != nil { 226 return err 227 } 228 if ok := rows.Next(); !ok { 229 break 230 } 231 } 232 233 return rows.Err() 234 }