mirror of
https://github.com/project-zot/zot.git
synced 2025-03-11 02:17:43 -05:00
ci/cd: add continuous benchmark action
Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
parent
72da8303c5
commit
6a2529f08f
4 changed files with 90 additions and 7 deletions
40
.github/workflows/benchmark.yaml
vendored
Normal file
40
.github/workflows/benchmark.yaml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
name: "Minimal Continuous Benchmark"
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
benchmark:
|
||||||
|
name: Performance regression check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.17.x
|
||||||
|
# Run benchmark with `go test -bench` and stores the output to a file
|
||||||
|
- name: Run benchmark
|
||||||
|
run: make BENCH_OUTPUT=ci-cd run-bench
|
||||||
|
# Download previous benchmark result from cache (if exists)
|
||||||
|
- name: Download previous benchmark data
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ./cache
|
||||||
|
key: ${{ runner.os }}-benchmark
|
||||||
|
# Run `github-action-benchmark` action
|
||||||
|
- name: Store benchmark result
|
||||||
|
uses: benchmark-action/github-action-benchmark@v1
|
||||||
|
with:
|
||||||
|
# What benchmark tool the output.txt came from
|
||||||
|
tool: 'customBiggerIsBetter'
|
||||||
|
# Where the output from the benchmark tool is stored
|
||||||
|
output-file-path: ci-cd.json
|
||||||
|
# Where the previous data file is stored
|
||||||
|
external-data-json-path: ./cache/benchmark-data.json
|
||||||
|
# Workflow will fail when an alert happens
|
||||||
|
fail-on-alert: true
|
||||||
|
# Upload the updated cache file for the next job by actions/cache
|
8
Makefile
8
Makefile
|
@ -12,6 +12,7 @@ GOLINTER := $(TOOLSDIR)/bin/golangci-lint
|
||||||
NOTATION := $(TOOLSDIR)/bin/notation
|
NOTATION := $(TOOLSDIR)/bin/notation
|
||||||
OS ?= linux
|
OS ?= linux
|
||||||
ARCH ?= amd64
|
ARCH ?= amd64
|
||||||
|
BENCH_OUTPUT ?= stdout
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: swagger binary binary-minimal binary-debug binary-arch binary-arch-minimal cli cli-arch bench bench-arch exporter-minimal verify-config test test-clean check
|
all: swagger binary binary-minimal binary-debug binary-arch binary-arch-minimal cli cli-arch bench bench-arch exporter-minimal verify-config test test-clean check
|
||||||
|
@ -64,6 +65,13 @@ test: check-skopeo $(NOTATION)
|
||||||
go test -tags extended,containers_image_openpgp -v -trimpath -race -timeout 15m -cover -coverpkg ./... -coverprofile=coverage-extended.txt -covermode=atomic ./...
|
go test -tags extended,containers_image_openpgp -v -trimpath -race -timeout 15m -cover -coverpkg ./... -coverprofile=coverage-extended.txt -covermode=atomic ./...
|
||||||
go test -tags minimal,containers_image_openpgp -v -trimpath -race -cover -coverpkg ./... -coverprofile=coverage-minimal.txt -covermode=atomic ./...
|
go test -tags minimal,containers_image_openpgp -v -trimpath -race -cover -coverpkg ./... -coverprofile=coverage-minimal.txt -covermode=atomic ./...
|
||||||
|
|
||||||
|
.PHONY: run-bench
|
||||||
|
run-bench: binary bench
|
||||||
|
bin/zot serve examples/config-minimal.json &
|
||||||
|
sleep 5
|
||||||
|
bin/zb -c 10 -n 100 -o $(BENCH_OUTPUT) http://localhost:8080
|
||||||
|
killall zot
|
||||||
|
|
||||||
.PHONY: test-clean
|
.PHONY: test-clean
|
||||||
test-clean:
|
test-clean:
|
||||||
$(shell sudo rm -rf /etc/containers/certs.d/127.0.0.1:8089/)
|
$(shell sudo rm -rf /etc/containers/certs.d/127.0.0.1:8089/)
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
func NewPerfRootCmd() *cobra.Command {
|
func NewPerfRootCmd() *cobra.Command {
|
||||||
showVersion := false
|
showVersion := false
|
||||||
|
|
||||||
var auth, workdir, repo, output string
|
var auth, workdir, repo, outFmt string
|
||||||
|
|
||||||
var concurrency, requests int
|
var concurrency, requests int
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ func NewPerfRootCmd() *cobra.Command {
|
||||||
|
|
||||||
requests = concurrency * (requests / concurrency)
|
requests = concurrency * (requests / concurrency)
|
||||||
|
|
||||||
Perf(workdir, url, auth, repo, concurrency, requests)
|
Perf(workdir, url, auth, repo, concurrency, requests, outFmt)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +59,8 @@ func NewPerfRootCmd() *cobra.Command {
|
||||||
"Number of multiple requests to make at a time")
|
"Number of multiple requests to make at a time")
|
||||||
rootCmd.Flags().IntVarP(&requests, "requests", "n", 1,
|
rootCmd.Flags().IntVarP(&requests, "requests", "n", 1,
|
||||||
"Number of requests to perform")
|
"Number of requests to perform")
|
||||||
rootCmd.Flags().StringVarP(&output, "output-format", "o", "",
|
rootCmd.Flags().StringVarP(&outFmt, "output-format", "o", "",
|
||||||
"Output format of test results [default: stdout]")
|
"Output format of test results: stdout (default), json, ci-cd")
|
||||||
|
|
||||||
// "version"
|
// "version"
|
||||||
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "show the version and exit")
|
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "show the version and exit")
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -33,6 +34,7 @@ const (
|
||||||
smallBlob = 1 * MiB
|
smallBlob = 1 * MiB
|
||||||
mediumBlob = 10 * MiB
|
mediumBlob = 10 * MiB
|
||||||
largeBlob = 100 * MiB
|
largeBlob = 100 * MiB
|
||||||
|
cicdFmt = "ci-cd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// helper routines
|
// helper routines
|
||||||
|
@ -198,7 +200,17 @@ func updateStats(summary *statsSummary, record statsRecord) {
|
||||||
summary.latencies = append(summary.latencies, record.latency)
|
summary.latencies = append(summary.latencies, record.latency)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printStats(requests int, summary *statsSummary) {
|
type cicdTestSummary struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Unit string `json:"unit"`
|
||||||
|
Value interface{} `json:"value"`
|
||||||
|
Range string `json:"range,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:gochecknoglobals // used only in this test
|
||||||
|
var cicdSummary = []cicdTestSummary{}
|
||||||
|
|
||||||
|
func printStats(requests int, summary *statsSummary, outFmt string) {
|
||||||
log.Printf("============\n")
|
log.Printf("============\n")
|
||||||
log.Printf("Test name:\t%s", summary.name)
|
log.Printf("Test name:\t%s", summary.name)
|
||||||
log.Printf("Time taken for tests:\t%v", summary.total)
|
log.Printf("Time taken for tests:\t%v", summary.total)
|
||||||
|
@ -219,6 +231,18 @@ func printStats(requests int, summary *statsSummary) {
|
||||||
log.Printf("%s:\t%v", "p90", summary.latencies[requests*9/10])
|
log.Printf("%s:\t%v", "p90", summary.latencies[requests*9/10])
|
||||||
log.Printf("%s:\t%v", "p99", summary.latencies[requests*99/100])
|
log.Printf("%s:\t%v", "p99", summary.latencies[requests*99/100])
|
||||||
log.Printf("\n")
|
log.Printf("\n")
|
||||||
|
|
||||||
|
// ci/cd
|
||||||
|
if outFmt == cicdFmt {
|
||||||
|
cicdSummary = append(cicdSummary,
|
||||||
|
cicdTestSummary{
|
||||||
|
Name: summary.name,
|
||||||
|
Unit: "requests per sec",
|
||||||
|
Value: summary.rps,
|
||||||
|
Range: "3",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test suites/funcs.
|
// test suites/funcs.
|
||||||
|
@ -644,7 +668,7 @@ var testSuite = []testConfig{ // nolint:gochecknoglobals // used only in this te
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func Perf(workdir, url, auth, repo string, concurrency int, requests int) {
|
func Perf(workdir, url, auth, repo string, concurrency int, requests int, outFmt string) {
|
||||||
// logging
|
// logging
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
log.SetOutput(tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.TabIndent))
|
log.SetOutput(tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.TabIndent))
|
||||||
|
@ -691,6 +715,17 @@ func Perf(workdir, url, auth, repo string, concurrency int, requests int) {
|
||||||
|
|
||||||
sort.Sort(Durations(summary.latencies))
|
sort.Sort(Durations(summary.latencies))
|
||||||
|
|
||||||
printStats(requests, &summary)
|
printStats(requests, &summary, outFmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if outFmt == cicdFmt {
|
||||||
|
jsonOut, err := json.Marshal(cicdSummary)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err) //nolint:gocritic // file closed on exit
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(fmt.Sprintf("%s.json", outFmt), jsonOut, defaultFilePerms); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue