k8s.io/kubernetes@v1.29.3/test/integration/benchmark/jsonify/main.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  	"os"
    24  
    25  	benchparse "golang.org/x/tools/benchmark/parse"
    26  )
    27  
    28  // TODO(random-liu): Replace this with prometheus' data model.
    29  
    30  // The following performance data structures are generalized and well-formatted.
    31  // They can be pretty printed in json format and be analyzed by other performance
    32  // analyzing tools, such as Perfdash (k8s.io/contrib/perfdash).
    33  
    34  // DataItem is the data point.
    35  type DataItem struct {
    36  	// Data is a map from bucket to real data point (e.g. "Perc90" -> 23.5). Notice
    37  	// that all data items with the same label combination should have the same buckets.
    38  	Data map[string]float64 `json:"data"`
    39  	// Unit is the data unit. Notice that all data items with the same label combination
    40  	// should have the same unit.
    41  	Unit string `json:"unit"`
    42  	// Labels is the labels of the data item.
    43  	Labels map[string]string `json:"labels,omitempty"`
    44  }
    45  
    46  // PerfData contains all data items generated in current test.
    47  type PerfData struct {
    48  	// Version is the version of the metrics. The metrics consumer could use the version
    49  	// to detect metrics version change and decide what version to support.
    50  	Version   string     `json:"version"`
    51  	DataItems []DataItem `json:"dataItems"`
    52  	// Labels is the labels of the dataset.
    53  	Labels map[string]string `json:"labels,omitempty"`
    54  }
    55  
    56  func main() {
    57  	err := run()
    58  	if err != nil {
    59  		panic(err)
    60  	}
    61  }
    62  
    63  func run() error {
    64  	if len(os.Args) < 2 {
    65  		return fmt.Errorf("output filename is a required argument")
    66  	}
    67  	benchmarkSet, err := benchparse.ParseSet(os.Stdin)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	data := PerfData{Version: "v1"}
    72  	for _, benchMarks := range benchmarkSet {
    73  		for _, benchMark := range benchMarks {
    74  			data.DataItems = appendIfMeasured(data.DataItems, benchMark, benchparse.NsPerOp, "time", "μs", benchMark.NsPerOp/1000.0)
    75  			data.DataItems = appendIfMeasured(data.DataItems, benchMark, benchparse.MBPerS, "throughput", "MBps", benchMark.MBPerS)
    76  			data.DataItems = appendIfMeasured(data.DataItems, benchMark, benchparse.AllocedBytesPerOp, "allocated", "bytes", float64(benchMark.AllocedBytesPerOp))
    77  			data.DataItems = appendIfMeasured(data.DataItems, benchMark, benchparse.AllocsPerOp, "allocations", "1", float64(benchMark.AllocsPerOp))
    78  			data.DataItems = appendIfMeasured(data.DataItems, benchMark, 0, "iterations", "1", float64(benchMark.N))
    79  		}
    80  	}
    81  	output := &bytes.Buffer{}
    82  	if err := json.NewEncoder(output).Encode(data); err != nil {
    83  		return err
    84  	}
    85  	formatted := &bytes.Buffer{}
    86  	if err := json.Indent(formatted, output.Bytes(), "", "  "); err != nil {
    87  		return err
    88  	}
    89  	return os.WriteFile(os.Args[1], formatted.Bytes(), 0664)
    90  }
    91  
    92  func appendIfMeasured(items []DataItem, benchmark *benchparse.Benchmark, metricType int, metricName string, unit string, value float64) []DataItem {
    93  	if metricType != 0 && (benchmark.Measured&metricType) == 0 {
    94  		return items
    95  	}
    96  	return append(items, DataItem{
    97  		Unit: unit,
    98  		Labels: map[string]string{
    99  			"benchmark":  benchmark.Name,
   100  			"metricName": metricName},
   101  		Data: map[string]float64{
   102  			"value": value}})
   103  }