0
0
mirror of https://gitlab.com/cznic/sqlite.git synced 2025-07-17 00:24:45 +00:00
Files
go-sqlite/benchmark/plot.go
2021-12-16 12:50:41 +00:00

237 lines
6.0 KiB
Go

// Copyright 2021 The Sqlite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// helpers for plotting benchmark results
package benchmark
import (
"fmt"
"os"
"path"
"github.com/wcharczuk/go-chart"
"github.com/wcharczuk/go-chart/drawing"
)
const (
yAxisCeilStep = 200000
)
var transparentColor = drawing.ColorWhite.WithAlpha(0)
type GraphCompareOfNRows struct {
// this fields should be set externally
rowCountsE []int
title string
palette chart.ColorPalette
// this fields are for private use
seriesNameS []string
seriesValuesS [][]float64
}
func (g *GraphCompareOfNRows) AddSeries(name string, values []float64) {
g.seriesNameS = append(g.seriesNameS, name)
g.seriesValuesS = append(g.seriesValuesS, values)
}
func (g *GraphCompareOfNRows) Render(filename string) error {
// new chart object
graph := g.newGraph()
// generate series objects for graph
for i, seriesName := range g.seriesNameS {
// get corresponding series values
seriesValues := g.seriesValuesS[i]
// create series object
graph.Series = append(graph.Series, g.createSeries(seriesName, seriesValues))
// adjust max for Y axis
yMax := (int(max(seriesValues...)/yAxisCeilStep) + 1) * yAxisCeilStep // a special case of ceil()
if graph.YAxis.Range.GetMax() < float64(yMax) {
graph.YAxis.Range = &chart.ContinuousRange{
Min: 0,
Max: float64(yMax),
}
}
// skip annotations for first series
if i == 0 {
continue
}
// for every series except first, we create a ratio annotation s[X]/s[0]
annotations := &chart.AnnotationSeries{}
for i, v := range seriesValues {
annotations.Annotations = append(annotations.Annotations, g.newRatioAnnotation(
float64(g.rowCountsE[i]),
v,
v/g.seriesValuesS[0][i],
))
}
// append annotations to graph
graph.Series = append(graph.Series, annotations)
}
// add legend
graph.Elements = []chart.Renderable{
chart.Legend(graph, chart.Style{
FontSize: 12,
StrokeColor: transparentColor,
FillColor: g.palette.CanvasColor(),
FontColor: g.palette.TextColor().WithAlpha(192),
}),
}
// write into file
if err := os.MkdirAll(path.Dir(filename), 0775); err != nil {
return err
}
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
if err := graph.Render(chart.PNG, f); err != nil {
return err
}
return nil
}
func (g *GraphCompareOfNRows) createSeries(name string, values []float64) chart.Series {
// convert E values of rowCount onto float64
var xValues []float64
for _, e := range g.rowCountsE {
xValues = append(xValues, float64(e))
}
// create series
series := &chart.ContinuousSeries{
Name: name,
Style: chart.Style{
DotWidth: 2.5,
Show: true,
StrokeWidth: 1.5,
},
XValues: xValues,
YValues: values,
}
// save in series slice
return series
}
func (g *GraphCompareOfNRows) newGraph() *chart.Chart {
return &chart.Chart{
ColorPalette: g.palette,
Title: g.title,
TitleStyle: chart.Style{
Show: true,
},
Background: chart.Style{
Padding: chart.Box{
Top: 20,
Left: 20,
},
},
Canvas: chart.Style{},
XAxis: chart.XAxis{
Style: chart.StyleShow(),
NameStyle: chart.StyleShow(),
Name: "rows",
Ticks: g.genXticks(),
},
YAxis: chart.YAxis{
Range: &chart.ContinuousRange{},
Style: chart.StyleShow(),
Name: "rows/sec",
NameStyle: chart.StyleShow(),
ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%.0f", v) },
},
}
}
func (g *GraphCompareOfNRows) newRatioAnnotation(x, y, ratio float64) chart.Value2 {
return chart.Value2{
XValue: x,
YValue: y,
Label: fmt.Sprintf("%.2fx", ratio),
Style: chart.Style{
FontSize: 8,
TextHorizontalAlign: chart.TextHorizontalAlignLeft,
FillColor: transparentColor, // full tranparency
StrokeColor: transparentColor, // full transparency
FontColor: g.palette.TextColor().WithAlpha(255), // no transaprency
TextRotationDegrees: 45,
},
}
}
func (g *GraphCompareOfNRows) genXticks() []chart.Tick {
var ticks []chart.Tick
for i, e := range g.rowCountsE {
ticks = append(ticks, chart.Tick{
Value: float64(e),
Label: fmt.Sprintf("1e%d", i+1),
})
}
return ticks
}
func max(f ...float64) float64 {
if len(f) == 0 {
return 0
}
m := f[0]
for i := 1; i < len(f); i++ {
if m < f[i] {
m = f[i]
}
}
return m
}
type palette struct {
bgColor drawing.Color
bgStrokeColor drawing.Color
canvasColor drawing.Color
canvasStrokeColor drawing.Color
axisStrokeColor drawing.Color
textColor drawing.Color
seriesColor []drawing.Color
}
func (p *palette) BackgroundColor() drawing.Color { return p.bgColor }
func (p *palette) BackgroundStrokeColor() drawing.Color { return p.bgStrokeColor }
func (p *palette) CanvasColor() drawing.Color { return p.canvasColor }
func (p *palette) CanvasStrokeColor() drawing.Color { return p.canvasStrokeColor }
func (p *palette) AxisStrokeColor() drawing.Color { return p.axisStrokeColor }
func (p *palette) TextColor() drawing.Color { return p.textColor }
func (p *palette) GetSeriesColor(i int) drawing.Color { return p.seriesColor[i%len(p.seriesColor)] }
var DarkPalette = &palette{
bgColor: drawing.ColorFromHex("252526"),
canvasColor: drawing.ColorFromHex("1e1e1e1"),
textColor: drawing.ColorFromHex("d4d4d4").WithAlpha(128),
axisStrokeColor: drawing.ColorFromHex("d4d4d4").WithAlpha(128),
seriesColor: []drawing.Color{
drawing.ColorFromHex("d5d5a5"),
drawing.ColorFromHex("569cd5"),
},
}
var LightPalette = &palette{
canvasColor: drawing.ColorFromHex("f2f2f2"),
bgColor: drawing.ColorFromHex("f5f5f5"),
textColor: drawing.ColorFromHex("393939").WithAlpha(128),
axisStrokeColor: drawing.ColorFromHex("393939").WithAlpha(128),
seriesColor: []drawing.Color{
drawing.ColorFromHex("aa3731"),
drawing.ColorFromHex("5a77c7"),
},
}