divide idle only benchmark and autopause benchmark of cpu usage
parent
a6fdc2f8ea
commit
52ddca0ea4
10
Makefile
10
Makefile
|
@ -924,9 +924,13 @@ endif
|
|||
stress: ## run the stress tests
|
||||
go test -test.v -test.timeout=2h ./test/stress -loops=10 | tee "./out/testout_$(COMMIT_SHORT).txt"
|
||||
|
||||
.PHONY: cpu-benchmark
|
||||
cpu-benchmark: ## run the cpu usage benchmark
|
||||
./hack/benchmark/cpu_usage/benchmark_local_k8s.sh
|
||||
.PHONY: cpu-benchmark-idle
|
||||
cpu-benchmark-idle: ## run the cpu usage 5 minutes idle benchmark
|
||||
./hack/benchmark/cpu_usage/idle_only/benchmark_local_k8s.sh
|
||||
|
||||
.PHONY: cpu-benchmark-autopause
|
||||
cpu-benchmark-autopause: ## run the cpu usage auto-pause benchmark
|
||||
./hack/benchmark/cpu_usage/auto_pause/benchmark_local_k8s.sh
|
||||
|
||||
.PHONY: update-gopogh-version
|
||||
update-gopogh-version: ## update gopogh version
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
# Gather data comparing the overhead of multiple local Kubernetes (macOS and linux)
|
||||
readonly TESTS=$1
|
||||
|
||||
# How many iterations to cycle through
|
||||
readonly TEST_ITERATIONS=10
|
||||
|
||||
# How long to poll CPU usage for (each point is an average over this period)
|
||||
readonly POLL_DURATION=5s
|
||||
|
||||
# How long to measure background usage for. 5 minutes too short, 10 minutes too long
|
||||
readonly TOTAL_DURATION=5m
|
||||
|
||||
# How all tests will be identified
|
||||
readonly SESSION_ID="$(date +%Y%m%d-%H%M%S)-$$"
|
||||
|
||||
# OS Type
|
||||
readonly OS=$(uname)
|
||||
|
||||
measure() {
|
||||
local name=$1
|
||||
local iteration=$2
|
||||
local totalduration=$3
|
||||
local filename="benchmark-results/${SESSION_ID}/cstat.${name}.$$-${iteration}"
|
||||
|
||||
echo ""
|
||||
echo " >> Current top processes by CPU:"
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
top -n 3 -l 2 -s 2 -o cpu | tail -n4 | awk '{ print $1 " " $2 " " $3 " " $4 }'
|
||||
elif [[ "${OS}" == "Linux" ]]; then
|
||||
top -b -n 3 -o %CPU | head -n 9
|
||||
fi
|
||||
|
||||
if [[ "${iteration}" == 0 ]]; then
|
||||
echo "NOTE: dry-run iteration: will not record measurements"
|
||||
cstat --poll "${POLL_DURATION}" --for "${POLL_DURATION}" --busy
|
||||
return
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " >> Measuring ${name} and saving to out/${filename} ..."
|
||||
if [[ "${totalduration}" != "" ]]; then
|
||||
cstat --poll "${POLL_DURATION}" --for "${totalduration}" --busy --header=false | tee "$(pwd)/out/${filename}"
|
||||
else
|
||||
cstat --poll "${POLL_DURATION}" --for "${TOTAL_DURATION}" --busy --header=false | tee "$(pwd)/out/${filename}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
cleanup() {
|
||||
echo " >> Deleting local clusters and Docker containers ..."
|
||||
out/minikube delete --all 2>/dev/null >/dev/null
|
||||
k3d cluster delete 2>/dev/null >/dev/null
|
||||
kind delete cluster 2>/dev/null >/dev/null
|
||||
docker stop $(docker ps -q) 2>/dev/null
|
||||
docker kill $(docker ps -q) 2>/dev/null
|
||||
docker rm $(docker ps -a -q) 2>/dev/null
|
||||
sleep 2
|
||||
}
|
||||
|
||||
pause_if_running_apps() {
|
||||
while true; do
|
||||
local apps=$(osascript -e 'tell application "System Events" to get name of (processes where background only is false)' | tr ',' '\n' | sed s/"^ "//g)
|
||||
local quiet=0
|
||||
|
||||
for app in $apps; do
|
||||
quiet=1
|
||||
if [[ "${app}" != "Terminal" && "${app}" != "Finder" ]]; then
|
||||
echo "Unexpected application running: \"${app}\" - will sleep"
|
||||
quiet=0
|
||||
fi
|
||||
done
|
||||
|
||||
pmset -g batt | grep 'AC Power'
|
||||
if [[ "$?" != 0 ]]; then
|
||||
echo "waiting to be plugged in ..."
|
||||
sleep 5
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "${quiet}" == 1 ]]; then
|
||||
break
|
||||
else
|
||||
echo "waiting for apps to be closed ..."
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
fail() {
|
||||
local name=$1
|
||||
local iteration=$2
|
||||
|
||||
echo '***********************************************************************'
|
||||
echo "${name} failed on iteration ${iteration} - will not record measurement"
|
||||
echo '***********************************************************************'
|
||||
|
||||
if [[ "${iteration}" == 0 ]]; then
|
||||
echo "test environment appears invalid, exiting"
|
||||
exit 90
|
||||
fi
|
||||
}
|
||||
|
||||
start_docker() {
|
||||
local docker_up=0
|
||||
local started=0
|
||||
|
||||
while [[ "${docker_up}" == 0 ]]; do
|
||||
docker info >/dev/null && docker_up=1 || docker_up=0
|
||||
|
||||
if [[ "${docker_up}" == 0 && "${started}" == 0 ]]; then
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
echo ""
|
||||
echo " >> Starting Docker for Desktop ..."
|
||||
open -a Docker
|
||||
started=1
|
||||
elif [[ "${OS}" == "Linux" ]]; then
|
||||
echo ""
|
||||
echo " >> Starting Docker Engine ..."
|
||||
sudo systemctl start docker
|
||||
started=1
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Give time for d4d Kubernetes to begin, if it's around
|
||||
if [[ "${started}" == 1 ]]; then
|
||||
sleep 60
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
main() {
|
||||
# check if cstat is installed
|
||||
CSTAT=$(which cstat)
|
||||
if [[ "$?" != 0 ]]; then
|
||||
echo "cstat in not installed. Install cstat at https://github.com/tstromberg/cstat"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "----[ versions ]------------------------------------"
|
||||
k3d version || { echo "k3d version failed. Please install latest k3d"; exit 1; }
|
||||
kind version || { echo "kind version failed. Please install latest kind"; exit 1; }
|
||||
out/minikube version || { echo "minikube version failed"; exit 1; }
|
||||
docker version
|
||||
echo "----------------------------------------------------"
|
||||
echo ""
|
||||
|
||||
echo "Session ID: ${SESSION_ID}"
|
||||
mkdir -p "out/benchmark-results/${SESSION_ID}"
|
||||
|
||||
echo ""
|
||||
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
echo "Turning on Wi-Fi for initial downloads"
|
||||
networksetup -setairportpower Wi-Fi on
|
||||
fi
|
||||
|
||||
for i in $(seq 0 ${TEST_ITERATIONS}); do
|
||||
echo ""
|
||||
echo "==> session ${SESSION_ID}, iteration $i"
|
||||
|
||||
cleanup
|
||||
|
||||
if [[ "$i" = 0 ]]; then
|
||||
echo "NOTE: The 0 iteration is an unmeasured dry run!"
|
||||
else
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
pause_if_running_apps
|
||||
echo "Turning off Wi-Fi to remove background noise"
|
||||
networksetup -setairportpower Wi-Fi off
|
||||
|
||||
echo " >> Killing Docker for Desktop ..."
|
||||
osascript -e 'quit app "Docker"'
|
||||
elif [[ "${OS}" == "Linux" ]]; then
|
||||
echo " >> Killing Docker Engine ..."
|
||||
sudo systemctl stop docker
|
||||
fi
|
||||
|
||||
# Measure the background noise on this system
|
||||
sleep 15
|
||||
measure idle $i
|
||||
fi
|
||||
|
||||
# Run cleanup once we can assert that Docker is up
|
||||
start_docker
|
||||
cleanup
|
||||
|
||||
docker_k8s=0
|
||||
# depending on whether Docker for Mac Kubernetes is enabled
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
# wait kubernetes system pods for Docker for Mac, if it is enabled
|
||||
sleep 60
|
||||
kubectl --context docker-desktop version
|
||||
|
||||
# measure Docker for Mac Kubernetes
|
||||
if [[ $? == 0 ]]; then
|
||||
echo "Kubernetes is running in Docker for Desktop - adjusting tests"
|
||||
docker_k8s=1
|
||||
kubectl create deployment nginx --image=nginx:1.20.0 && measure docker_k8s $i
|
||||
echo "end of measurement for Docker for Desktop"
|
||||
kubectl delete deployment nginx
|
||||
# measure Docker idle
|
||||
else
|
||||
kubectl create deployment nginx --image=nginx:1.20.0
|
||||
measure docker $i
|
||||
echo "end of measurement for Docker for Desktop Kubernetes"
|
||||
kubectl delete deployment nginx
|
||||
fi
|
||||
# measure Docker idle only
|
||||
elif [[ "${OS}" == "Linux" ]]; then
|
||||
measure docker $i
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "-> k3d"
|
||||
time k3d cluster create
|
||||
echo "-> deploy nginx deployment"
|
||||
kubectl create deployment nginx --image=nginx:1.20.0 && measure k3d $i || fail k3d $i
|
||||
cleanup
|
||||
|
||||
echo ""
|
||||
echo "-> kind"
|
||||
time kind create cluster
|
||||
echo "-> deploy nginx deployment"
|
||||
kubectl create deployment nginx --image=nginx:1.20.0 && measure kind $i || fail kind $i
|
||||
cleanup
|
||||
|
||||
# test different drivers
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
drivers=(docker hyperkit virtualbox)
|
||||
elif [[ "${OS}" == "Linux" ]]; then
|
||||
drivers=(docker kvm2 virtualbox)
|
||||
fi
|
||||
|
||||
for driver in "${drivers[@]}"; do
|
||||
echo ""
|
||||
# 1. start minikube cluster
|
||||
echo "-> out/minikube --driver=${driver}"
|
||||
time out/minikube start --driver "${driver}"
|
||||
|
||||
#2. deploy sample application(nginx deployment) and 3. wait 1 minute without anything and 4. measure No.3 idle CPU usage
|
||||
echo "-> deploy nginx deployment"
|
||||
kubectl create deployment nginx --image=nginx:1.20.0 && measure "minikube.${driver}.nonautopause" $i "1m" || fail "minikube.${driver}.nonautopause" $i
|
||||
|
||||
# 5. enable auto-pause addons and 6. wait 3 minute without anything and measure No.6 idle CPU usage
|
||||
echo "-> enable auto-pause to control plane"
|
||||
out/minikube addons enable auto-pause && measure "minikube.${driver}.autopause" $i "3m" || fail "minikube.${driver}.autopause" $i
|
||||
cleanup
|
||||
|
||||
# We won't be needing docker for the remaining tests this iteration
|
||||
if [[ "${OS}" == "Darwin" && "${driver}" == "docker" ]]; then
|
||||
echo " >> Quitting Docker for Desktop ..."
|
||||
osascript -e 'quit app "Docker"'
|
||||
elif [[ "${OS}" == "Linux" && ${driver} == "docker" ]]; then
|
||||
echo " >> Quitting Docker Engine ..."
|
||||
sudo systemctl stop docker
|
||||
fi
|
||||
done ## driver
|
||||
done ## iteration
|
||||
}
|
||||
|
||||
main "$@"
|
||||
# update benchmark result into docs contents
|
||||
./hack/benchmark/cpu_usage/auto_pause/update_summary.sh "${SESSION_ID}"
|
||||
go run ./hack/benchmark/cpu_usage/auto_pause/chart.go "${SESSION_ID}"
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
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 (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gonum.org/v1/plot"
|
||||
"gonum.org/v1/plot/plotter"
|
||||
"gonum.org/v1/plot/plotutil"
|
||||
"gonum.org/v1/plot/vg"
|
||||
)
|
||||
|
||||
var FOLDER = "site/static/images/benchmarks/cpuUsage/autoPause"
|
||||
|
||||
type integerTicks struct{}
|
||||
|
||||
func (integerTicks) Ticks(min, max float64) []plot.Tick {
|
||||
var t []plot.Tick
|
||||
for i := math.Trunc(min); i <= max; i += 50 {
|
||||
t = append(t, plot.Tick{Value: i, Label: fmt.Sprint(i)})
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func execute() error {
|
||||
// sessionID is generated and used at cpu usage benchmark
|
||||
sessionID := os.Args[1]
|
||||
if len(sessionID) == 0 {
|
||||
return errors.New("Please identify sessionID")
|
||||
}
|
||||
|
||||
// Create plot instance
|
||||
p := plot.New()
|
||||
|
||||
// Set view options
|
||||
if runtime.GOOS == "darwin" {
|
||||
p.Title.Text = "CPU% Busy Overhead - With Auto Pause vs. Non Auto Pause (less is better)"
|
||||
} else if runtime.GOOS == "linux" {
|
||||
p.Title.Text = "CPU% Busy Overhead - With Auto Pause vs. Non Auto Pause (less is better)"
|
||||
}
|
||||
p.Y.Label.Text = "CPU overhead%"
|
||||
|
||||
// Open non-autopause csv file of benchmark summary
|
||||
napResults := []float64{}
|
||||
var napFn string = "./out/benchmark-results/" + sessionID + "/cstat.nonautopause.summary"
|
||||
napFile, err := os.Open(napFn)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Missing summary csv")
|
||||
}
|
||||
defer napFile.Close()
|
||||
|
||||
// Read result values from benchmark summary csv
|
||||
napReader := csv.NewReader(napFile)
|
||||
var napLine []string
|
||||
for {
|
||||
napLine, err = napReader.Read()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
s, err := strconv.ParseFloat(napLine[0], 64)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to convert to float64")
|
||||
}
|
||||
napResults = append(napResults, s)
|
||||
}
|
||||
|
||||
// Open auto-pause csv file of benchmark summary
|
||||
apResults := []float64{}
|
||||
var apFn string = "./out/benchmark-results/" + sessionID + "/cstat.autopause.summary"
|
||||
apFile, err := os.Open(apFn)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Missing summary csv")
|
||||
}
|
||||
defer apFile.Close()
|
||||
|
||||
// Read result values from benchmark summary csv
|
||||
apReader := csv.NewReader(apFile)
|
||||
var apLine []string
|
||||
for {
|
||||
apLine, err = apReader.Read()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
s, err := strconv.ParseFloat(apLine[0], 64)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to convert to float64")
|
||||
}
|
||||
apResults = append(apResults, s)
|
||||
}
|
||||
|
||||
// Set bar graph width
|
||||
breadth := vg.Points(40)
|
||||
|
||||
// Create Bar instance with non-autopause benchmark results
|
||||
barNAP, err := plotter.NewBarChart(plotter.Values(napResults), breadth)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to create bar chart")
|
||||
}
|
||||
|
||||
// Set border of the bar graph. 0 is no border color
|
||||
barNAP.LineStyle.Width = vg.Length(0)
|
||||
// Add bar name
|
||||
p.Legend.Add("Initial start CPU usage", barNAP)
|
||||
// Set bar color. 2 is blue
|
||||
barNAP.Color = plotutil.Color(2)
|
||||
|
||||
// Create Bar instance with auto-pause benchmark results
|
||||
barAP, err := plotter.NewBarChart(plotter.Values(apResults), breadth)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to create bar chart")
|
||||
}
|
||||
|
||||
// Set border of the bar graph. 0 is no border color
|
||||
barAP.LineStyle.Width = vg.Length(0)
|
||||
// Add bar name
|
||||
p.Legend.Add("Auto-paused CPU usage", barAP)
|
||||
// Set bar color. 1 is green
|
||||
barAP.Color = plotutil.Color(1)
|
||||
|
||||
hb := vg.Points(20)
|
||||
barNAP.Offset = -hb
|
||||
barAP.Offset = hb
|
||||
p.Add(barNAP, barAP)
|
||||
|
||||
// Set legend position upper
|
||||
p.Legend.Top = true
|
||||
|
||||
// Add x-lay names
|
||||
if runtime.GOOS == "darwin" {
|
||||
p.NominalX("OS idle", "minikube hyperkit", "minikube virtualbox", "minikube docker", "Docker for Mac Kubernetes", "k3d", "kind")
|
||||
} else if runtime.GOOS == "linux" {
|
||||
p.NominalX("OS idle", "minikube kvm2", "minikube virtualbox", "minikube docker", "Docker idle", "k3d", "kind")
|
||||
}
|
||||
p.X.Label.Text = "Tools"
|
||||
|
||||
// Set non-autopause data label to each bar
|
||||
var napLabels []string
|
||||
for i := range napResults {
|
||||
nLabel := strconv.FormatFloat(napResults[i], 'f', -1, 64)
|
||||
napLabels = append(napLabels, nLabel)
|
||||
}
|
||||
|
||||
var napCPU []plotter.XY
|
||||
for i := range napResults {
|
||||
napXPos := float64(i)-0.25
|
||||
napYPos := napResults[i]+0.1
|
||||
napXY := plotter.XY{X: napXPos, Y: napYPos}
|
||||
napCPU = append(napCPU, napXY)
|
||||
}
|
||||
// CPU Busy% non-autopause data label
|
||||
napl, err := plotter.NewLabels(plotter.XYLabels{
|
||||
XYs: napCPU,
|
||||
Labels: napLabels,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("could not creates labels plotter: %+v", err)
|
||||
}
|
||||
|
||||
// Set auto-pause data label to each bar
|
||||
var apLabels []string
|
||||
for i := range apResults {
|
||||
if apResults[i] == 0 {
|
||||
apLabels = append(apLabels, "N/A")
|
||||
} else {
|
||||
apLabel := strconv.FormatFloat(apResults[i], 'f', -1, 64)
|
||||
apLabels = append(apLabels, apLabel)
|
||||
}
|
||||
}
|
||||
|
||||
var apCPU []plotter.XY
|
||||
for i := range apResults {
|
||||
apXPos := float64(i)+0.05
|
||||
apYPos := apResults[i]+0.1
|
||||
apXY := plotter.XY{X: apXPos, Y: apYPos}
|
||||
apCPU = append(apCPU, apXY)
|
||||
}
|
||||
// CPU Busy% auto-pause data label
|
||||
apl, err := plotter.NewLabels(plotter.XYLabels{
|
||||
XYs: apCPU,
|
||||
Labels: apLabels,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("could not creates labels plotter: %+v", err)
|
||||
}
|
||||
var t []plot.Tick
|
||||
for i := math.Trunc(0); i <= 300; i += 50 {
|
||||
t = append(t, plot.Tick{Value: i, Label: fmt.Sprint(i)})
|
||||
}
|
||||
// define max cpu busy% to 20%
|
||||
p.Y.Max = 20
|
||||
p.Y.Tick.Marker = integerTicks{}
|
||||
// Add CPU Busy% label to plot
|
||||
p.Add(napl, apl)
|
||||
|
||||
// Output bar graph
|
||||
if runtime.GOOS == "darwin" {
|
||||
if err := p.Save(13*vg.Inch, 8*vg.Inch, FOLDER+"/mac.png"); err != nil {
|
||||
return errors.Wrap(err, "Failed to create bar graph png")
|
||||
}
|
||||
log.Printf("Generated graph png to %s/mac.png", FOLDER)
|
||||
} else if runtime.GOOS == "linux" {
|
||||
if err := p.Save(13*vg.Inch, 10*vg.Inch, FOLDER+"/linux.png"); err != nil {
|
||||
return errors.Wrap(err, "Failed to create bar graph png")
|
||||
}
|
||||
log.Printf("Generated graph png to %s/linux.png", FOLDER)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
SESSION_ID=$1
|
||||
|
||||
NONAUTOPAUSE_RESULTS=()
|
||||
AUTOPAUSE_RESULTS=()
|
||||
OS=$(uname)
|
||||
|
||||
if [[ ${OS} == "Darwin" ]]; then
|
||||
TESTS_TARGETS=("idle" "minikube.hyperkit" "minikube.virtualbox" "minikube.docker" "docker" "k3d" "kind")
|
||||
elif [[ ${OS} == "Linux" ]]; then
|
||||
TESTS_TARGETS=("idle" "minikube.kvm2" "minikube.virtualbox" "minikube.docker" "docker" "k3d" "kind")
|
||||
fi
|
||||
|
||||
# calc average each non-autopause test target
|
||||
calcAvarageNonAutopause() {
|
||||
for target in ${TESTS_TARGETS[@]}; do
|
||||
nap_count=0;
|
||||
nap_total=0;
|
||||
if [[ "${target}" == "minikube."* ]]; then
|
||||
FILES=$(ls out/benchmark-results/${SESSION_ID} | grep cstat.${target} | grep nonautopause)
|
||||
else
|
||||
FILES=$(ls out/benchmark-results/${SESSION_ID} | grep cstat.${target})
|
||||
fi
|
||||
|
||||
# calc average per test target
|
||||
for file in ${FILES[@]}; do
|
||||
NAP_MEASURED=$(cat out/benchmark-results/${SESSION_ID}/${file} | tail -n 1)
|
||||
nap_total=$(echo ${nap_total}+${NAP_MEASURED} | bc )
|
||||
((nap_count++))
|
||||
done
|
||||
|
||||
NONAUTOPAUSE_RESULT=$(echo "scale=4; ${nap_total} / ${nap_count}" | bc | awk '{printf "%.4f\n", $0}')
|
||||
NONAUTOPAUSE_RESULTS=("${NONAUTOPAUSE_RESULTS[@]}" ${NONAUTOPAUSE_RESULT})
|
||||
done
|
||||
}
|
||||
|
||||
# calc average each autopause test target
|
||||
calcAvarageAutopause() {
|
||||
for target in ${TESTS_TARGETS[@]}; do
|
||||
if [[ "${target}" == "minikube."* ]]; then
|
||||
ap_count=0;
|
||||
ap_total=0;
|
||||
FILES=$(ls out/benchmark-results/${SESSION_ID} | grep cstat.${target} | grep autopause)
|
||||
# calc average per test target
|
||||
for file in ${FILES[@]}; do
|
||||
AP_MEASURED=$(cat out/benchmark-results/${SESSION_ID}/${file} | tail -n 1)
|
||||
ap_total=$(echo ${ap_total}+${AP_MEASURED} | bc )
|
||||
((ap_count++))
|
||||
done
|
||||
|
||||
AUTOPAUSE_RESULT=$(echo "scale=4; ${ap_total} / ${ap_count}" | bc | awk '{printf "%.4f\n", $0}')
|
||||
AUTOPAUSE_RESULTS=("${AUTOPAUSE_RESULTS[@]}" ${AUTOPAUSE_RESULT})
|
||||
else
|
||||
AUTOPAUSE_RESULTS=("${AUTOPAUSE_RESULTS[@]}" 0)
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# create non-autopause summary csv
|
||||
updateNonAutopauseSummary() {
|
||||
for ((i = 0; i < ${#NONAUTOPAUSE_RESULTS[@]}; i++)) {
|
||||
echo "${NONAUTOPAUSE_RESULTS[i]}" >> out/benchmark-results/${SESSION_ID}/cstat.nonautopause.summary
|
||||
}
|
||||
}
|
||||
|
||||
# create autopause summary csv
|
||||
updateAutopauseSummary() {
|
||||
for ((i = 0; i < ${#AUTOPAUSE_RESULTS[@]}; i++)) {
|
||||
echo "${AUTOPAUSE_RESULTS[i]}" >> out/benchmark-results/${SESSION_ID}/cstat.autopause.summary
|
||||
}
|
||||
}
|
||||
|
||||
calcAvarageNonAutopause
|
||||
updateNonAutopauseSummary
|
||||
|
||||
calcAvarageAutopause
|
||||
updateAutopauseSummary
|
|
@ -0,0 +1,25 @@
|
|||
# What is these scripts
|
||||
These scripts are for the benchmark of cpu usage, minikube vs kind vs k3d.
|
||||
|
||||
* `benchmark_local_k8s.sh`: take benchmark for cpu usage. This will take long to take place
|
||||
* `update_summary.sh`: create one summary csv file of each drivers and products
|
||||
* `chart.go`: create bar chart graph as a png file
|
||||
|
||||
In `benchmark_local_k8s.sh`, we compare minikube drivers(hyperkit, virtualbox, docker, docker with auto-pause) and kind, k3d, Docker for Mac Kubernetes in case of macOS.
|
||||
In `benchmark_local_k8s.sh`, we compare minikube drivers(kvm2, virtualbox, docker, docker with auto-pause) and kind, k3d in case of Linux.
|
||||
|
||||
# How to use these scripts
|
||||
|
||||
```
|
||||
cd <Top of minikube directory>
|
||||
make cpu-benchmark
|
||||
```
|
||||
|
||||
After running `make cpu-benchmark`, the png file of the bar chart graph will be generated.
|
||||
If you update the benchmark results to [our website](https://minikube.sigs.k8s.io/docs/benchmarks/), please commit this change.
|
||||
|
||||
```
|
||||
git status
|
||||
git add <Changed png file>
|
||||
git commit
|
||||
```
|
|
@ -220,50 +220,35 @@ main() {
|
|||
measure docker $i
|
||||
fi
|
||||
|
||||
# measure k3d and kind, if Docker for Mac kubernetes is disable
|
||||
if [[ "${OS}" == "Darwin" && "${docker_k8s}" == 1 ]]; then
|
||||
echo "Dcoker for Mac Kubernetes is running. Skip k3d and kind measurement"
|
||||
else
|
||||
echo ""
|
||||
echo "-> k3d"
|
||||
time k3d cluster create && measure k3d $i || fail k3d $i
|
||||
cleanup
|
||||
# measure k3d and kind
|
||||
echo ""
|
||||
echo "-> k3d"
|
||||
time k3d cluster create && measure k3d $i || fail k3d $i
|
||||
cleanup
|
||||
|
||||
echo ""
|
||||
echo "-> kind"
|
||||
time kind create cluster && measure kind $i || fail kind $i
|
||||
cleanup
|
||||
fi
|
||||
echo ""
|
||||
echo "-> kind"
|
||||
time kind create cluster && measure kind $i || fail kind $i
|
||||
cleanup
|
||||
|
||||
# test different drivers
|
||||
if [[ "${OS}" == "Darwin" ]]; then
|
||||
drivers=(docker docker-autopause hyperkit virtualbox)
|
||||
drivers=(docker hyperkit virtualbox)
|
||||
elif [[ "${OS}" == "Linux" ]]; then
|
||||
drivers=(docker docker-autopause kvm2 virtualbox)
|
||||
drivers=(docker kvm2 virtualbox)
|
||||
fi
|
||||
|
||||
for driver in "${drivers[@]}"; do
|
||||
if [[ "${OS}" == "Darwin" && "${docker_k8s}" == 1 && "${driver}" == "docker" ]]; then
|
||||
echo " >> Quitting Docker for Desktop ..."
|
||||
osascript -e 'quit app "Docker"'
|
||||
continue
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [[ "${driver}" == "docker-autopause" ]]; then
|
||||
echo "-> out/minikube --driver=${driver} --addons=auto-pause"
|
||||
time out/minikube start --driver docker --addons auto-pause && measure "minikube.${driver}" $i || fail "minikube.${driver}" $i
|
||||
else
|
||||
echo "-> out/minikube --driver=${driver}"
|
||||
time out/minikube start --driver "${driver}" && measure "minikube.${driver}" $i || fail "minikube.${driver}" $i
|
||||
fi
|
||||
echo "-> out/minikube --driver=${driver}"
|
||||
time out/minikube start --driver "${driver}" && measure "minikube.${driver}" $i || fail "minikube.${driver}" $i
|
||||
cleanup
|
||||
|
||||
# We won't be needing docker for the remaining tests this iteration
|
||||
if [[ "${OS}" == "Darwin" && "${driver}" == "docker-autopause" ]]; then
|
||||
if [[ "${OS}" == "Darwin" && "${driver}" == "docker" ]]; then
|
||||
echo " >> Quitting Docker for Desktop ..."
|
||||
osascript -e 'quit app "Docker"'
|
||||
elif [[ "${OS}" == "Linux" && ${driver} == "docker-autopause" ]]; then
|
||||
elif [[ "${OS}" == "Linux" && ${driver} == "docker" ]]; then
|
||||
echo " >> Quitting Docker Engine ..."
|
||||
sudo systemctl stop docker
|
||||
fi
|
||||
|
@ -273,5 +258,5 @@ main() {
|
|||
|
||||
main "$@"
|
||||
# update benchmark result into docs contents
|
||||
./hack/benchmark/cpu_usage/update_summary.sh "${SESSION_ID}"
|
||||
go run ./hack/benchmark/cpu_usage/chart.go "${SESSION_ID}"
|
||||
./hack/benchmark/cpu_usage/idle_only/update_summary.sh "${SESSION_ID}"
|
||||
go run ./hack/benchmark/cpu_usage/idle_only/chart.go "${SESSION_ID}"
|
|
@ -32,6 +32,8 @@ import (
|
|||
"gonum.org/v1/plot/vg"
|
||||
)
|
||||
|
||||
var FOLDER = "site/static/images/benchmarks/cpuUsage/idleOnly"
|
||||
|
||||
type integerTicks struct{}
|
||||
|
||||
func (integerTicks) Ticks(min, max float64) []plot.Tick {
|
||||
|
@ -113,9 +115,9 @@ func execute() error {
|
|||
|
||||
// Add x-lay names
|
||||
if runtime.GOOS == "darwin" {
|
||||
p.NominalX("OS idle", "minikube hyperkit", "minikube virtualbox", "minikube docker", "minikube docker auto-pause", "Docker for Mac Kubernetes", "k3d", "kind")
|
||||
p.NominalX("OS idle", "minikube hyperkit", "minikube virtualbox", "minikube docker", "Docker for Mac Kubernetes", "k3d", "kind")
|
||||
} else if runtime.GOOS == "linux" {
|
||||
p.NominalX("OS idle", "minikube kvm2", "minikube virtualbox", "minikube docker", "minikube docker auto-pause", "Docker idle", "k3d", "kind")
|
||||
p.NominalX("OS idle", "minikube kvm2", "minikube virtualbox", "minikube docker", "Docker idle", "k3d", "kind")
|
||||
}
|
||||
p.X.Label.Text = "Tools"
|
||||
|
||||
|
@ -142,30 +144,27 @@ func execute() error {
|
|||
if err != nil {
|
||||
log.Fatalf("could not creates labels plotter: %+v", err)
|
||||
}
|
||||
//for i := range rl.TextStyle {
|
||||
// rl.TextStyle[i].Color = color.RGBA{R: 255, A: 255}
|
||||
//}
|
||||
var t []plot.Tick
|
||||
for i := math.Trunc(0); i <= 300; i += 50 {
|
||||
t = append(t, plot.Tick{Value: i, Label: fmt.Sprint(i)})
|
||||
}
|
||||
// define max cpu busy% to 30%
|
||||
p.Y.Max = 30
|
||||
// define max cpu busy% to 20%
|
||||
p.Y.Max = 20
|
||||
p.Y.Tick.Marker = integerTicks{}
|
||||
// Add CPU Busy% label to plot
|
||||
p.Add(cl)
|
||||
|
||||
// Output bar graph
|
||||
if runtime.GOOS == "darwin" {
|
||||
if err := p.Save(13*vg.Inch, 8*vg.Inch, "./site/static/images/benchmarks/cpuUsage/mac.png"); err != nil {
|
||||
if err := p.Save(13*vg.Inch, 8*vg.Inch, FOLDER+"/mac.png"); err != nil {
|
||||
return errors.Wrap(err, "Failed to create bar graph png")
|
||||
}
|
||||
log.Printf("Generated graph png to 'site/static/images/benchmarks/cpuUsage/mac.png'")
|
||||
log.Printf("Generated graph png to %s/mac.png", FOLDER)
|
||||
} else if runtime.GOOS == "linux" {
|
||||
if err := p.Save(13*vg.Inch, 10*vg.Inch, "./site/static/images/benchmarks/cpuUsage/linux.png"); err != nil {
|
||||
if err := p.Save(13*vg.Inch, 10*vg.Inch, FOLDER+"/linux.png"); err != nil {
|
||||
return errors.Wrap(err, "Failed to create bar graph png")
|
||||
}
|
||||
log.Printf("Generated graph png to 'site/static/images/benchmarks/cpuUsage/linux.png'")
|
||||
log.Printf("Generated graph png to %s/linux.png", FOLDER)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -20,9 +20,9 @@ RESULTS=()
|
|||
OS=$(uname)
|
||||
|
||||
if [[ ${OS} == "Darwin" ]]; then
|
||||
TESTS_TARGETS=("idle" "minikube.hyperkit" "minikube.virtualbox" "minikube.docker" "minikube.docker-autopause" "docker" "k3d" "kind")
|
||||
TESTS_TARGETS=("idle" "minikube.hyperkit" "minikube.virtualbox" "minikube.docker" "docker" "k3d" "kind")
|
||||
elif [[ ${OS} == "Linux" ]]; then
|
||||
TESTS_TARGETS=("idle" "minikube.kvm2" "minikube.virtualbox" "minikube.docker" "minikube.docker-autopause" "docker" "k3d" "kind")
|
||||
TESTS_TARGETS=("idle" "minikube.kvm2" "minikube.virtualbox" "minikube.docker" "docker" "k3d" "kind")
|
||||
fi
|
||||
|
||||
# calc average each test target
|
||||
|
@ -30,7 +30,7 @@ calcAvarage() {
|
|||
for target in ${TESTS_TARGETS[@]}; do
|
||||
count=0;
|
||||
total=0;
|
||||
FILES=$(ls out/benchmark-results/${SESSION_ID} | grep cstat.${target})
|
||||
FILES=$(ls out/benchmark-results/${SESSION_ID} | grep cstat.${target})
|
||||
|
||||
# calc average per test target
|
||||
for file in ${FILES[@]}; do
|
|
@ -1,113 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"log"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"gonum.org/v1/plot"
|
||||
"gonum.org/v1/plot/plotter"
|
||||
"gonum.org/v1/plot/vg"
|
||||
)
|
||||
|
||||
type integerTicks struct{}
|
||||
|
||||
func (integerTicks) Ticks(min, max float64) []plot.Tick {
|
||||
var t []plot.Tick
|
||||
for i := math.Trunc(min); i <= max; i += 50 {
|
||||
t = append(t, plot.Tick{Value: i, Label: fmt.Sprint(i)})
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func main() {
|
||||
red := plotter.Values{213, 206, 256, 256, 16, 122, 291}
|
||||
black := plotter.Values{16, 86, 109, 290, 42, 257, 9}
|
||||
|
||||
days := []string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
|
||||
|
||||
p := plot.New()
|
||||
|
||||
redC := color.RGBA{R: 255, A: 255}
|
||||
blackC := color.RGBA{R: 196, G: 196, A: 255}
|
||||
|
||||
w := vg.Points(8)
|
||||
|
||||
redBars, err := plotter.NewBarChart(red, w)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
redBars.Color = redC
|
||||
redBars.Offset = -w
|
||||
|
||||
blackBars, err := plotter.NewBarChart(black, w)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
blackBars.Color = blackC
|
||||
blackBars.Offset = w
|
||||
|
||||
p.Add(blackBars, redBars)
|
||||
p.NominalX(days...)
|
||||
|
||||
var redLabels []string
|
||||
var blackLabels []string
|
||||
|
||||
for i := range red {
|
||||
rLabel := strconv.FormatFloat(red[i], 'f', -1, 64)
|
||||
bLabel := strconv.FormatFloat(black[i], 'f', -1, 64)
|
||||
|
||||
redLabels = append(redLabels, rLabel)
|
||||
blackLabels = append(blackLabels, bLabel)
|
||||
}
|
||||
|
||||
var xysR, xysB []plotter.XY
|
||||
|
||||
for i := range red {
|
||||
rxPos, bxPos := float64(i)-0.5, float64(i)+0.1
|
||||
ryPos, byPos := red[i]+5, black[i]+5
|
||||
|
||||
rXY := plotter.XY{X: rxPos, Y: ryPos}
|
||||
bXY := plotter.XY{X: bxPos, Y: byPos}
|
||||
|
||||
xysR = append(xysR, rXY)
|
||||
xysB = append(xysB, bXY)
|
||||
}
|
||||
|
||||
rl, err := plotter.NewLabels(plotter.XYLabels{
|
||||
XYs: xysR,
|
||||
Labels: redLabels,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("could not creates labels plotter: %+v", err)
|
||||
}
|
||||
for i := range rl.TextStyle {
|
||||
rl.TextStyle[i].Color = color.RGBA{R: 255, A: 255}
|
||||
//fmt.Println(r, i)
|
||||
}
|
||||
|
||||
bl, err := plotter.NewLabels(plotter.XYLabels{
|
||||
XYs: xysB,
|
||||
Labels: blackLabels,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("could not creates labels plotter: %+v", err)
|
||||
}
|
||||
|
||||
var t []plot.Tick
|
||||
for i := math.Trunc(0); i <= 300; i += 50 {
|
||||
t = append(t, plot.Tick{Value: i, Label: fmt.Sprint(i)})
|
||||
}
|
||||
p.Y.Max = 310
|
||||
p.Y.Tick.Marker = integerTicks{}
|
||||
|
||||
p.Add(rl, bl)
|
||||
|
||||
if err := p.Save(4*vg.Inch, 4*vg.Inch, "points.png"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -4,4 +4,27 @@ linkTitle: "CPU Usage Benchmarks(Linux)"
|
|||
weight: 1
|
||||
---
|
||||
|
||||

|
||||
## CPU% Busy Overhead - Avarage first 5 minutes only
|
||||
|
||||
This chart shows each tool's CPU busy overhead percentage.
|
||||
After each tool's starting, we measured each tool's idle for 5 minutes.
|
||||
This chart was measured only after the start without deploying any pods.
|
||||
|
||||

|
||||
|
||||
## CPU% Busy Overhead - With Auto Pause vs. Non Auto Pause
|
||||
|
||||
This chart shows each tool's CPU busy overhead percentage with auto-pause addon.
|
||||
The auto-pause is mechanism which reduce CPU busy usage by pausing kube-apiserver.
|
||||
This chart was measured with the following steps.
|
||||
By these steps, we compare CPU usage with auto-pause vs. non-auto-pause.
|
||||
|
||||
1. start each local kubernetes tool
|
||||
2. deploy sample application(nginx deployment)
|
||||
3. wait 1 minute without anything
|
||||
4. measure No.3 idle CPU usage with [cstat](https://github.com/tstromberg/cstat)
|
||||
5. enable auto-pause addons(only if tool is minikube)
|
||||
6. wait 3 minute without anything
|
||||
7. measure No.6 idle CPU usage with [cstat](https://github.com/tstromberg/cstat)
|
||||
|
||||

|
|
@ -4,4 +4,30 @@ linkTitle: "CPU Usage Benchmarks(macOS)"
|
|||
weight: 1
|
||||
---
|
||||
|
||||

|
||||
## CPU% Busy Overhead - Avarage first 5 minutes only
|
||||
|
||||
This chart shows each tool's CPU busy overhead percentage.
|
||||
After each tool's starting, we measured each tool's idle for 5 minutes.
|
||||
This chart was measured only after the start without deploying any pods.
|
||||
|
||||
1. start each local kubernetes tool
|
||||
2. measure its cpu usage with [cstat](https://github.com/tstromberg/cstat)
|
||||
|
||||

|
||||
|
||||
## CPU% Busy Overhead - With Auto Pause vs. Non Auto Pause
|
||||
|
||||
This chart shows each tool's CPU busy overhead percentage with auto-pause addon.
|
||||
The auto-pause is mechanism which reduce CPU busy usage by pausing kube-apiserver.
|
||||
This chart was measured with the following steps.
|
||||
By these steps, we compare CPU usage with auto-pause vs. non-auto-pause.
|
||||
|
||||
1. start each local kubernetes tool
|
||||
2. deploy sample application(nginx deployment)
|
||||
3. wait 1 minute without anything
|
||||
4. measure No.3 idle CPU usage with [cstat](https://github.com/tstromberg/cstat)
|
||||
5. enable auto-pause addons(only if tool is minikube)
|
||||
6. wait 3 minute without anything
|
||||
7. measure No.6 idle CPU usage with [cstat](https://github.com/tstromberg/cstat)
|
||||
|
||||

|
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
Loading…
Reference in New Issue