github.com/distbuild/reclient@v0.0.0-20240401075343-3de72e395564/experiments/cmd/exprunner/main.go (about) 1 // Copyright 2023 Google LLC 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 main is the main package for the experiment exprunner binary. 16 // 17 // Use the exprunner tool to run experiments defined in an experiment textproto 18 // file, tabulate them into a bigquery table, and upload results to perfgate. 19 // Example: 20 // bazelisk run //experiments/cmd/exprunner:exprunner -- --exp_def_path=$PWD/experiments/examples/chrome-build.textproto --perfgate_path="reclient_perfgate" --benchmark_path=$PWD/tests/performance/benchmarks/chrome-perfgate.config 21 // 22 // To view logging info as the experiment is running, run with --alsologtostderr. 23 package main 24 25 import ( 26 "flag" 27 "os" 28 "path/filepath" 29 "text/template" 30 31 "github.com/bazelbuild/reclient/experiments/internal/pkg/perfgate" 32 "github.com/bazelbuild/reclient/experiments/internal/pkg/runner" 33 "github.com/bazelbuild/reclient/experiments/internal/pkg/tabulator" 34 35 "github.com/bazelbuild/remote-apis-sdks/go/pkg/moreflag" 36 37 log "github.com/golang/glog" 38 ) 39 40 var ( 41 gcpProject = flag.String("gcp_project", "foundry-x-experiments", "Name of the GCP project to run experiments on. Defaults to foundry-x-experiments.") 42 resBucket = flag.String("results_bucket", "foundry-x-experiments-results", "Name of the GCS bucket to store results. Defaults to foundry-x-experiments-results.") 43 expDefPath = flag.String("exp_def_path", "", "Path to the .textproto file containing the experiment definition. If none specified, does not run. If exp_def_vars is provided then this file will be parsed as a text/template.") 44 dateSuffix = flag.String("date_suffix", "", "Date string suffix to use instead of checking the current time. If none specified, the current time will be used.") 45 perfgatePath = flag.String("perfgate_path", "", "Path to the perfgate wrapper binary. If none specified, results will not be uploaded to perfgate.") 46 benchmarkFile = flag.String("benchmark_path", "", "Path to the BenchmarkInfo file containing metric definitions.") 47 logFrequency = flag.Int("log_frequency", -1, "Time between polling the log file for updates, in seconds. Default 5 for virtual machine experiments, 0 (disabled) for workstation experiments") 48 expDefVars map[string]string 49 ) 50 51 func main() { 52 flag.Var((*moreflag.StringMapValue)(&expDefVars), "exp_def_vars", "Comma-separated key value pairs in the form key=value to be used in exp_def_path file in the form {{.key}}.") 53 54 flag.Parse() 55 if *expDefPath == "" { 56 log.Fatal("exp_def_path cannot be empty.") 57 } 58 if len(expDefVars) > 0 { 59 filledTemplate := generateExpDefFromTemplate(*expDefPath, expDefVars) 60 defer os.Remove(filledTemplate) 61 *expDefPath = filledTemplate 62 } 63 log.Infof("Running experiment: %v", *expDefPath) 64 expName, err := runner.RunExperiment(*expDefPath, *dateSuffix, *gcpProject, *resBucket, *logFrequency) 65 if err != nil { 66 log.Fatalf("Error running experiment: %v", err) 67 } 68 log.Infof("Running tabulator on experiment: %v", expName) 69 if err := tabulator.RunExperimentResultCollector(*resBucket, expName, *gcpProject); err != nil { 70 log.Fatalf("Error running tabulator: %v", err) 71 } 72 log.Infof("Done tabulating results for %v", expName) 73 if *perfgatePath != "" { 74 log.Infof("Uploading results to perfgate using: %v", *perfgatePath) 75 if err := perfgate.RunUploader(*expDefPath, *resBucket, expName, *gcpProject, *perfgatePath, *benchmarkFile); err != nil { 76 log.Fatalf("Error running perfgate: %v", err) 77 } 78 } 79 } 80 81 func generateExpDefFromTemplate(tmplPath string, tmplMap map[string]string) string { 82 log.Infof("Populating template") 83 f, err := os.CreateTemp("", filepath.Base(tmplPath)) 84 defer f.Close() 85 if err != nil { 86 log.Fatalf("Error creating tmp file: %w", err) 87 } 88 tmpl, err := template.ParseFiles(tmplPath) 89 if err != nil { 90 log.Fatalf("Error parsing template file: %w", err) 91 } 92 err = tmpl.Execute(f, tmplMap) 93 if err != nil { 94 log.Fatalf("Error generating experiment definition file from template: %w") 95 } 96 return f.Name() 97 }