gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/tools/parsers/parser_main.go (about) 1 // Copyright 2020 The gVisor Authors. 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 // Binary parser parses Benchmark data from golang benchmarks, 16 // puts it into a Schema for BigQuery, and sends it to BigQuery. 17 // parser will also initialize a table with the Benchmarks BigQuery schema. 18 package main 19 20 import ( 21 "context" 22 "fmt" 23 "io/ioutil" 24 "log" 25 "os" 26 27 "gvisor.dev/gvisor/runsc/flag" 28 bq "gvisor.dev/gvisor/tools/bigquery" 29 "gvisor.dev/gvisor/tools/parsers" 30 ) 31 32 const ( 33 initString = "init" 34 initDescription = "initializes a new table with benchmarks schema" 35 parseString = "parse" 36 parseDescription = "parses given benchmarks file and sends it to BigQuery table." 37 ) 38 39 var ( 40 // The init command will create a new dataset/table in the given project and initialize 41 // the table with the schema in //tools/bigquery/bigquery.go. If the table/dataset exists 42 // or has been initialized, init has no effect and successfully returns. 43 initCmd = flag.NewFlagSet(initString, flag.ContinueOnError) 44 initProject = initCmd.String("project", "", "GCP project to send benchmarks.") 45 initDataset = initCmd.String("dataset", "", "dataset to send benchmarks data.") 46 initTable = initCmd.String("table", "", "table to send benchmarks data.") 47 48 // The parse command parses benchmark data in `file` and sends it to the 49 // requested table. 50 parseCmd = flag.NewFlagSet(parseString, flag.ContinueOnError) 51 file = parseCmd.String("file", "", "file to parse for benchmarks") 52 name = parseCmd.String("suite_name", "", "name of the benchmark suite") 53 parseProject = parseCmd.String("project", "", "GCP project to send benchmarks.") 54 parseDataset = parseCmd.String("dataset", "", "dataset to send benchmarks data.") 55 parseTable = parseCmd.String("table", "", "table to send benchmarks data.") 56 official = parseCmd.Bool("official", false, "mark input data as official.") 57 runtime = parseCmd.String("runtime", "", "runtime used to run the benchmark") 58 debug = parseCmd.Bool("debug", false, "print debug logs") 59 ) 60 61 // initBenchmarks initializes a dataset/table in a BigQuery project. 62 func initBenchmarks(ctx context.Context) error { 63 return bq.InitBigQuery(ctx, *initProject, *initDataset, *initTable, nil) 64 } 65 66 // parseBenchmarks parses the given file into the BigQuery schema, 67 // adds some custom data for the commit, and sends the data to BigQuery. 68 func parseBenchmarks(ctx context.Context) error { 69 debugLog("Reading file: %s", *file) 70 data, err := ioutil.ReadFile(*file) 71 if err != nil { 72 return fmt.Errorf("failed to read file %s: %v", *file, err) 73 } 74 debugLog("Parsing output: %s", string(data)) 75 suite, err := parsers.ParseOutput(string(data), *name, *official) 76 if err != nil { 77 return fmt.Errorf("failed parse data: %v", err) 78 } 79 debugLog("Parsed benchmarks: %d", len(suite.Benchmarks)) 80 if len(suite.Benchmarks) < 1 { 81 fmt.Fprintf(os.Stderr, "Failed to find benchmarks for file: %s", *file) 82 return nil 83 } 84 85 extraConditions := []*bq.Condition{ 86 { 87 Name: "runtime", 88 Value: *runtime, 89 }, 90 { 91 Name: "version", 92 Value: version, 93 }, 94 } 95 96 suite.Official = *official 97 suite.Conditions = append(suite.Conditions, extraConditions...) 98 debugLog("Sending benchmarks") 99 return bq.SendBenchmarks(ctx, suite, *parseProject, *parseDataset, *parseTable, nil) 100 } 101 102 func main() { 103 ctx := context.Background() 104 switch { 105 // the "init" command 106 case len(os.Args) >= 2 && os.Args[1] == initString: 107 if err := initCmd.Parse(os.Args[2:]); err != nil { 108 log.Fatalf("Failed parse flags: %v\n", err) 109 os.Exit(1) 110 } 111 if err := initBenchmarks(ctx); err != nil { 112 failure := "failed to initialize project: %s dataset: %s table: %s: %v\n" 113 log.Fatalf(failure, *parseProject, *parseDataset, *parseTable, err) 114 os.Exit(1) 115 } 116 // the "parse" command. 117 case len(os.Args) >= 2 && os.Args[1] == parseString: 118 if err := parseCmd.Parse(os.Args[2:]); err != nil { 119 log.Fatalf("Failed parse flags: %v\n", err) 120 os.Exit(1) 121 } 122 if err := parseBenchmarks(ctx); err != nil { 123 log.Fatalf("Failed parse benchmarks: %v\n", err) 124 os.Exit(1) 125 } 126 default: 127 printUsage() 128 os.Exit(1) 129 } 130 } 131 132 // printUsage prints the top level usage string. 133 func printUsage() { 134 usage := `Usage: parser <command> <flags> ... 135 136 Available commands: 137 %s %s 138 %s %s 139 ` 140 log.Printf(usage, initCmd.Name(), initDescription, parseCmd.Name(), parseDescription) 141 } 142 143 func debugLog(msg string, args ...any) { 144 if *debug { 145 log.Printf(msg, args...) 146 } 147 }