[benchmark] add cpu utilization

pull/13654/head
Jin Zhang 2022-02-22 07:16:09 +00:00
parent 49afc90a41
commit 7bd8639fbc
4 changed files with 264 additions and 32 deletions

View File

@ -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) {

View File

@ -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
}

View File

@ -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()
}

View File

@ -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