[benchmark] add cpu utilization
parent
49afc90a41
commit
7bd8639fbc
|
@ -19,10 +19,8 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
|
@ -45,27 +43,12 @@ type run struct {
|
|||
type runs struct {
|
||||
version string
|
||||
runs []run
|
||||
cpus []cpu
|
||||
}
|
||||
|
||||
func main() {
|
||||
csvPath := flag.String("csv", "", "path to the CSV file")
|
||||
chartPath := flag.String("output", "", "path to output the chart to")
|
||||
flag.Parse()
|
||||
|
||||
// map of the apps (minikube, kind, k3d) and their runs
|
||||
apps := make(map[string]runs)
|
||||
|
||||
if err := readInCSV(*csvPath, apps); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
values, totals, names := values(apps)
|
||||
|
||||
outputMarkdownTable(values, totals, names)
|
||||
|
||||
if err := createChart(*chartPath, values, totals, names); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
type cpu struct {
|
||||
cpuPct float64 // percentage
|
||||
cpuTime float64 // second
|
||||
}
|
||||
|
||||
func readInCSV(csvPath string, apps map[string]runs) error {
|
||||
|
@ -92,7 +75,7 @@ func readInCSV(csvPath string, apps map[string]runs) error {
|
|||
values := []float64{}
|
||||
|
||||
// 8-13 contain the run results
|
||||
for i := 8; i <= 13; i++ {
|
||||
for i := 8; i <= 16; i++ {
|
||||
v, err := strconv.ParseFloat(d[i], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -100,6 +83,7 @@ func readInCSV(csvPath string, apps map[string]runs) error {
|
|||
values = append(values, v)
|
||||
}
|
||||
newRun := run{values[0], values[1], values[2], values[3], values[4], values[5]}
|
||||
newCPU := cpu{values[6], values[8]}
|
||||
|
||||
// get the app from the map and add the new run to it
|
||||
name := d[0]
|
||||
|
@ -108,14 +92,18 @@ func readInCSV(csvPath string, apps map[string]runs) error {
|
|||
k = runs{version: d[5]}
|
||||
}
|
||||
k.runs = append(k.runs, newRun)
|
||||
k.cpus = append(k.cpus, newCPU)
|
||||
apps[name] = k
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func values(apps map[string]runs) ([]plotter.Values, []float64, []string) {
|
||||
func values(apps map[string]runs) ([]plotter.Values, []plotter.Values, []plotter.Values, []float64, []string) {
|
||||
var cmdValues, apiValues, k8sValues, dnsSvcValues, appValues, dnsAnsValues plotter.Values
|
||||
var cpuPctValues, cpuTimeValues plotter.Values
|
||||
var cpuMinikube, cpuKind, cpuK3d plotter.Values
|
||||
|
||||
names := []string{}
|
||||
totals := []float64{}
|
||||
|
||||
|
@ -123,6 +111,8 @@ func values(apps map[string]runs) ([]plotter.Values, []float64, []string) {
|
|||
for _, name := range []string{"minikube", "kind", "k3d"} {
|
||||
app := apps[name]
|
||||
var cmd, api, k8s, dnsSvc, appRun, dnsAns float64
|
||||
var cpuPct, cpuTime float64
|
||||
|
||||
names = append(names, app.version)
|
||||
|
||||
for _, l := range app.runs {
|
||||
|
@ -134,6 +124,11 @@ func values(apps map[string]runs) ([]plotter.Values, []float64, []string) {
|
|||
dnsAns += l.dnsAns
|
||||
}
|
||||
|
||||
for _, l := range app.cpus {
|
||||
cpuPct += l.cpuPct
|
||||
cpuTime += l.cpuTime
|
||||
}
|
||||
|
||||
c := float64(len(app.runs))
|
||||
|
||||
cmdAvg := cmd / c
|
||||
|
@ -143,6 +138,9 @@ func values(apps map[string]runs) ([]plotter.Values, []float64, []string) {
|
|||
appAvg := appRun / c
|
||||
dnsAnsAvg := dnsAns / c
|
||||
|
||||
cpuPctAvg := cpuPct / c
|
||||
cpuTimeAvg := cpuTime / c
|
||||
|
||||
cmdValues = append(cmdValues, cmdAvg)
|
||||
apiValues = append(apiValues, apiAvg)
|
||||
k8sValues = append(k8sValues, k8sAvg)
|
||||
|
@ -152,11 +150,32 @@ func values(apps map[string]runs) ([]plotter.Values, []float64, []string) {
|
|||
|
||||
total := cmdAvg + apiAvg + k8sAvg + dnsSvcAvg + appAvg + dnsAnsAvg
|
||||
totals = append(totals, total)
|
||||
|
||||
cpuPctValues = append(cpuPctValues, cpuPctAvg)
|
||||
cpuTimeValues = append(cpuTimeValues, cpuTimeAvg)
|
||||
|
||||
cpuSummary := []float64{cpuPctAvg, cpuTimeAvg}
|
||||
|
||||
switch name {
|
||||
case "minikube":
|
||||
cpuMinikube = cpuSummary
|
||||
case "kind":
|
||||
cpuKind = cpuSummary
|
||||
case "k3d":
|
||||
cpuK3d = cpuSummary
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
values := []plotter.Values{cmdValues, apiValues, k8sValues, dnsSvcValues, appValues, dnsAnsValues}
|
||||
runningTime := []plotter.Values{cmdValues, apiValues, k8sValues, dnsSvcValues, appValues, dnsAnsValues}
|
||||
|
||||
return values, totals, names
|
||||
// for markdown table, row is either cpu utilization or cpu time, col is process name
|
||||
cpu := []plotter.Values{cpuPctValues, cpuTimeValues}
|
||||
|
||||
// row is process name, col is either cpu utilization, or cpu time
|
||||
cpureverse := []plotter.Values{cpuMinikube, cpuKind, cpuK3d}
|
||||
|
||||
return runningTime, cpu, cpureverse, totals, names
|
||||
}
|
||||
|
||||
func outputMarkdownTable(categories []plotter.Values, totals []float64, names []string) {
|
||||
|
@ -184,7 +203,7 @@ func outputMarkdownTable(categories []plotter.Values, totals []float64, names []
|
|||
t.SetCenterSeparator("|")
|
||||
t.AppendBulk(c)
|
||||
t.Render()
|
||||
fmt.Println(b.String())
|
||||
data.TimeMarkdown = b.String()
|
||||
}
|
||||
|
||||
func createChart(chartPath string, values []plotter.Values, totals []float64, names []string) error {
|
||||
|
@ -252,7 +271,13 @@ func createChart(chartPath string, values []plotter.Values, totals []float64, na
|
|||
|
||||
p.Add(l)
|
||||
|
||||
return p.Save(12*vg.Inch, 8*vg.Inch, chartPath)
|
||||
if err := p.Save(12*vg.Inch, 8*vg.Inch, chartPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data.TimeChart = chartPath
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createBars(values plotter.Values, index int) (*plotter.BarChart, error) {
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"gonum.org/v1/plot"
|
||||
"gonum.org/v1/plot/plotter"
|
||||
"gonum.org/v1/plot/plotutil"
|
||||
"gonum.org/v1/plot/vg"
|
||||
)
|
||||
|
||||
var fields = []string{"CPU Utilization(%)", "CPU Time(seconds)"}
|
||||
|
||||
func cpuMarkdownTable(categories []plotter.Values, names []string) {
|
||||
|
||||
// categories row is the either cpu pct or time, col is process name
|
||||
headers := append([]string{""}, names...)
|
||||
c := [][]string{}
|
||||
for i, values := range categories {
|
||||
row := []string{fields[i]}
|
||||
for _, value := range values {
|
||||
row = append(row, fmt.Sprintf("%.3f", value))
|
||||
}
|
||||
c = append(c, row)
|
||||
}
|
||||
b := new(bytes.Buffer)
|
||||
t := tablewriter.NewWriter(b)
|
||||
t.SetAutoWrapText(false)
|
||||
t.SetHeader(headers)
|
||||
t.SetAutoFormatHeaders(false)
|
||||
t.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
|
||||
t.SetCenterSeparator("|")
|
||||
t.AppendBulk(c)
|
||||
t.Render()
|
||||
data.CPUMarkdown = b.String()
|
||||
}
|
||||
|
||||
func createCPUChart(chartPath string, values []plotter.Values, names []string) error {
|
||||
p := plot.New()
|
||||
p.Title.Text = "CPU utilization to go from 0 to successful Kubernetes deployment"
|
||||
p.Y.Label.Text = "CPU utilization"
|
||||
|
||||
w := vg.Points(20)
|
||||
|
||||
barsA, err := plotter.NewBarChart(values[0], w)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
barsA.LineStyle.Width = vg.Length(0)
|
||||
barsA.Color = plotutil.Color(0)
|
||||
barsA.Offset = -w
|
||||
|
||||
barsB, err := plotter.NewBarChart(values[1], w)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
barsB.LineStyle.Width = vg.Length(0)
|
||||
barsB.Color = plotutil.Color(1)
|
||||
barsB.Offset = 0
|
||||
|
||||
barsC, err := plotter.NewBarChart(values[2], w)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
barsC.LineStyle.Width = vg.Length(0)
|
||||
barsC.Color = plotutil.Color(2)
|
||||
barsC.Offset = w
|
||||
|
||||
p.Add(barsA, barsB, barsC)
|
||||
p.Legend.Add(names[0], barsA)
|
||||
p.Legend.Add(names[1], barsB)
|
||||
p.Legend.Add(names[2], barsC)
|
||||
|
||||
p.Legend.Top = true
|
||||
p.NominalX(fields...)
|
||||
|
||||
if err := p.Save(8*vg.Inch, 8*vg.Inch, chartPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data.CPUChart = chartPath
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
var page = `---
|
||||
title: "{{.Version}} Benchmark"
|
||||
linkTitle: "{{.Version}} Benchmark"
|
||||
weight: -{{.Weight}}
|
||||
---
|
||||
|
||||
![time-to-k8s]({{.TimeChart}})
|
||||
|
||||
{{.TimeMarkdown}}
|
||||
|
||||
|
||||
![cpu-to-k8s]({{.CPUChart}})
|
||||
|
||||
{{.CPUMarkdown}}
|
||||
`
|
||||
|
||||
type Data struct {
|
||||
Version string
|
||||
Weight string
|
||||
TimeChart string
|
||||
TimeMarkdown string
|
||||
CPUChart string
|
||||
CPUMarkdown string
|
||||
}
|
||||
|
||||
var data Data
|
||||
|
||||
func main() {
|
||||
csvPath := flag.String("csv", "", "path to the CSV file")
|
||||
imagePath := flag.String("image", "", "path to output the chart to")
|
||||
pagePath := flag.String("page", "", "path to output the page to")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
t := time.Now()
|
||||
data.Weight = fmt.Sprintf("%d%d%d", t.Year(), t.Month(), t.Day())
|
||||
|
||||
// map of the apps (minikube, kind, k3d) and their runs
|
||||
apps := make(map[string]runs)
|
||||
|
||||
if err := readInCSV(*csvPath, apps); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
runningTime, cpuMdPlot, cpuChartPlot, totals, names := values(apps)
|
||||
|
||||
// markdown table for running time
|
||||
outputMarkdownTable(runningTime, totals, names)
|
||||
|
||||
// chart for running time
|
||||
if err := createChart(*imagePath+"-time.png", runningTime, totals, names); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// markdown table for cpu utilization
|
||||
cpuMarkdownTable(cpuMdPlot, names)
|
||||
|
||||
// chart for cpu utilization
|
||||
if err := createCPUChart(*imagePath+"-cpu.png", cpuChartPlot, names); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// generate page and save
|
||||
tmpl, err := template.New("msg").Parse(page)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Create(*pagePath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err = tmpl.Execute(f, data); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
f.Close()
|
||||
|
||||
}
|
|
@ -37,12 +37,10 @@ run_benchmark() {
|
|||
go run . --config local-kubernetes.yaml --iterations 10 --output output.csv )
|
||||
}
|
||||
|
||||
generate_chart() {
|
||||
go run ./hack/benchmark/time-to-k8s/chart.go --csv ./hack/benchmark/time-to-k8s/time-to-k8s-repo/output.csv --output ./site/static/images/benchmarks/timeToK8s/"$1".png >> ./site/content/en/docs/benchmarks/timeToK8s/"$1".md
|
||||
}
|
||||
|
||||
# create page and generate chart inside the code
|
||||
create_page() {
|
||||
printf -- "---\ntitle: \"%s Benchmark\"\nlinkTitle: \"%s Benchmark\"\nweight: -$(date +'%Y%m%d')\n---\n\n![time-to-k8s](/images/benchmarks/timeToK8s/%s.png)\n" "$1" "$1" "$1" > ./site/content/en/docs/benchmarks/timeToK8s/"$1".md
|
||||
go run ./hack/benchmark/time-to-k8s/*.go --csv ./hack/benchmark/time-to-k8s/time-to-k8s-repo/output.csv --image ./site/static/images/benchmarks/timeToK8s/"$1" --page ./site/content/en/docs/benchmarks/timeToK8s/"$1".md
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
|
@ -56,5 +54,4 @@ install_minikube
|
|||
VERSION=$(minikube version --short)
|
||||
run_benchmark
|
||||
create_page "$VERSION"
|
||||
generate_chart "$VERSION"
|
||||
cleanup
|
||||
|
|
Loading…
Reference in New Issue