benchmarks/runner/main.go (174 lines of code) (raw):

// Copyright (c) 2023 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package main import ( "bufio" "bytes" "flag" "io/ioutil" "os" "os/exec" "path" "runtime" "strings" "time" yaml "github.com/ghodss/yaml" "github.com/kardianos/osext" "go.uber.org/zap" "go.uber.org/zap/zapcore" "github.com/uber/zanzibar/test/lib/util" ) var logger = zap.New( zapcore.NewCore( zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), os.Stderr, zap.DebugLevel, ), ) func spawnBenchServer(dirName string) *exec.Cmd { benchServerPath := path.Join(dirName, "..", "benchserver", "benchserver") var benchServerCmd *exec.Cmd if runtime.GOOS == "linux" { benchServerCmd = exec.Command("taskset", "-c", "1,2", benchServerPath) } else { benchServerCmd = exec.Command(benchServerPath) } benchServerCmd.Stdout = os.Stdout benchServerCmd.Stderr = os.Stderr err := benchServerCmd.Start() if err != nil { panic(err) } return benchServerCmd } func writeConfigToFile(config map[string]interface{}) (string, error) { tempConfigDir, err := ioutil.TempDir("", "zanzibar-bench-config-yaml") if err != nil { return "", err } configFile := path.Join(tempConfigDir, "production.yaml") if _, err := os.Stat(configFile); os.IsNotExist(err) { configFile = path.Join(tempConfigDir, "production.json") } configBytes, err := yaml.Marshal(config) if err != nil { return "", err } err = ioutil.WriteFile(configFile, configBytes, os.ModePerm) if err != nil { return "", err } return configFile, nil } func spawnGateway(dirName string) *exec.Cmd { logTempDir, err := ioutil.TempDir("", "zanzibar-log-file") if err != nil { panic(err) } config := map[string]interface{}{ "http.port": 8093, "tchannel.serviceName": "bench-gateway", "tchannel.processName": "bench-gateway", "metrics.m3.hostPort": "127.0.0.1:8053", "metrics.serviceName": "bench-gateway", "logger.fileName": path.Join(logTempDir, "zanzibar.log"), "logger.output": "disk", "clients.contacts.port": 8092, "clients.google-now.port": 8092, "clients.baz.port": 8094, "clients.contacts.ip": "127.0.0.1", } configFiles := util.DefaultConfigFiles("example-gateway") tempConfigFile, err := writeConfigToFile(config) if err != nil { panic(err) } configFiles = append(configFiles, tempConfigFile) configOption := strings.Join(configFiles, ";") mainGatewayPath := path.Join( dirName, "..", "..", "examples", "example-gateway", "bin", "example-gateway", ) var gatewayCmd *exec.Cmd if runtime.GOOS == "linux" { gatewayCmd = exec.Command( "taskset", "-c", "0,3", mainGatewayPath, "-config", configOption) } else { gatewayCmd = exec.Command(mainGatewayPath, "-config", configOption) } gatewayCmd.Env = append(gatewayCmd.Env, "ENVIRONMENT=production") gatewayCmd.Stderr = os.Stderr gatewayCmd.Stdout = os.Stdout err = gatewayCmd.Start() if err != nil { panic(err) } logger.Info("started main gateway", zap.String("baseYamlFile", tempConfigFile), ) return gatewayCmd } func main() { execFile, err := osext.Executable() if err != nil { panic(err) } dirName := path.Dir(execFile) defaultBenchProgram := path.Join(dirName, "..", "contacts_1KB.lua") loadtest := flag.Bool("loadtest", false, "turn on wrk load testing") luaScript := flag.String("script", defaultBenchProgram, "wrk lua script to run") flag.Parse() cwd, err := os.Getwd() if err != nil { panic(err) } var loadTestScript string if path.IsAbs(*luaScript) { loadTestScript = *luaScript } else { loadTestScript = path.Join(cwd, *luaScript) } benchServerCmd := spawnBenchServer(dirName) gatewayCmd := spawnGateway(dirName) if *loadtest { spawnWrkLoadTest(loadTestScript) err = gatewayCmd.Process.Kill() if err != nil { panic(err) } err = benchServerCmd.Process.Kill() if err != nil { panic(err) } } else { err = gatewayCmd.Wait() if err != nil { panic(err) } err = benchServerCmd.Wait() if err != nil { panic(err) } } } func spawnWrkLoadTest(loadTestScript string) { loadTestContent, err := ioutil.ReadFile(loadTestScript) if err != nil { panic(err) } reader := bufio.NewReader(bytes.NewReader(loadTestContent)) line, _ := reader.ReadString('\n') // First line is the wrk Command line = line[3 : len(line)-1] segments := strings.Split(line, " ") time.Sleep(2 * time.Second) logger.Info("spawning wrk child process\n") wrkCmd := exec.Command("wrk", segments[1:]...) wrkCmd.Stdout = os.Stdout wrkCmd.Stderr = os.Stderr err = wrkCmd.Start() if err != nil { panic(err) } err = wrkCmd.Wait() if err != nil { panic(err) } }