// Copyright 2020 The gVisor Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Binary parser parses Benchmark data from golang benchmarks, // puts it into a Schema for BigQuery, and sends it to BigQuery. // parser will also initialize a table with the Benchmarks BigQuery schema. package main import ( "context" "fmt" "io/ioutil" "os" "gvisor.dev/gvisor/runsc/flag" bq "gvisor.dev/gvisor/tools/bigquery" "gvisor.dev/gvisor/tools/parsers" ) const ( initString = "init" initDescription = "initializes a new table with benchmarks schema" parseString = "parse" parseDescription = "parses given benchmarks file and sends it to BigQuery table." ) var ( // The init command will create a new dataset/table in the given project and initialize // the table with the schema in //tools/bigquery/bigquery.go. If the table/dataset exists // or has been initialized, init has no effect and successfully returns. initCmd = flag.NewFlagSet(initString, flag.ContinueOnError) initProject = initCmd.String("project", "", "GCP project to send benchmarks.") initDataset = initCmd.String("dataset", "", "dataset to send benchmarks data.") initTable = initCmd.String("table", "", "table to send benchmarks data.") // The parse command parses benchmark data in `file` and sends it to the // requested table. parseCmd = flag.NewFlagSet(parseString, flag.ContinueOnError) file = parseCmd.String("file", "", "file to parse for benchmarks") name = parseCmd.String("suite_name", "", "name of the benchmark suite") clNumber = parseCmd.String("cl", "", "changelist number of this run") gitCommit = parseCmd.String("git_commit", "", "git commit sha for this run") parseProject = parseCmd.String("project", "", "GCP project to send benchmarks.") parseDataset = parseCmd.String("dataset", "", "dataset to send benchmarks data.") parseTable = parseCmd.String("table", "", "table to send benchmarks data.") official = parseCmd.Bool("official", false, "mark input data as official.") ) // initBenchmarks initializes a dataset/table in a BigQuery project. func initBenchmarks(ctx context.Context) error { return bq.InitBigQuery(ctx, *initProject, *initDataset, *initTable, nil) } // parseBenchmarks parses the given file into the BigQuery schema, // adds some custom data for the commit, and sends the data to BigQuery. func parseBenchmarks(ctx context.Context) error { data, err := ioutil.ReadFile(*file) if err != nil { return fmt.Errorf("failed to read file: %v", err) } suite, err := parsers.ParseOutput(string(data), *name, *official) if err != nil { return fmt.Errorf("failed parse data: %v", err) } extraConditions := []*bq.Condition{ { Name: "change_list", Value: *clNumber, }, { Name: "commit", Value: *gitCommit, }, } suite.Conditions = append(suite.Conditions, extraConditions...) return bq.SendBenchmarks(ctx, suite, *parseProject, *parseDataset, *parseTable, nil) } func main() { ctx := context.Background() switch { // the "init" command case len(os.Args) >= 2 && os.Args[1] == initString: if err := initCmd.Parse(os.Args[2:]); err != nil { fmt.Fprintf(os.Stderr, "failed parse flags: %v", err) os.Exit(1) } if err := initBenchmarks(ctx); err != nil { failure := "failed to initialize project: %s dataset: %s table: %s: %v" fmt.Fprintf(os.Stderr, failure, *parseProject, *parseDataset, *parseTable, err) os.Exit(1) } // the "parse" command. case len(os.Args) >= 2 && os.Args[1] == parseString: if err := parseCmd.Parse(os.Args[2:]); err != nil { fmt.Fprintf(os.Stderr, "failed parse flags: %v", err) os.Exit(1) } if err := parseBenchmarks(ctx); err != nil { fmt.Fprintf(os.Stderr, "failed parse benchmarks: %v", err) os.Exit(1) } default: printUsage() } } // printUsage prints the top level usage string. func printUsage() { usage := `Usage: parser ... Available commands: %s %s %s %s ` fmt.Fprintf(os.Stderr, usage, initCmd.Name(), initDescription, parseCmd.Name(), parseDescription) }