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  }