Files
go-jdenticon/internal/renderer/renderer_bench_test.go
Kevin McIntyre f1544ef49c
Some checks failed
CI / Test (Go 1.24.x, ubuntu-latest) (push) Successful in 1m53s
CI / Code Quality (push) Failing after 26s
CI / Security Scan (push) Failing after 11s
CI / Test Coverage (push) Successful in 1m13s
CI / Benchmarks (push) Failing after 10m22s
CI / Build CLI (push) Failing after 8s
Benchmarks / Run Benchmarks (push) Failing after 10m13s
Release / Test (push) Successful in 55s
Release / Build (amd64, darwin, ) (push) Failing after 12s
Release / Build (amd64, linux, ) (push) Failing after 6s
Release / Build (amd64, windows, .exe) (push) Failing after 12s
Release / Build (arm64, darwin, ) (push) Failing after 12s
Release / Build (arm64, linux, ) (push) Failing after 12s
Release / Release (push) Has been skipped
CI / Test (Go 1.24.x, macos-latest) (push) Has been cancelled
CI / Test (Go 1.24.x, windows-latest) (push) Has been cancelled
chore: update module path to gitea.dockr.co/kev/go-jdenticon
Move hosting from GitHub to private Gitea instance.
2026-02-10 10:07:57 -05:00

465 lines
10 KiB
Go

package renderer
import (
"testing"
"gitea.dockr.co/kev/go-jdenticon/internal/engine"
)
var benchmarkSizes = []int{
16, 32, 64, 128, 256, 512,
}
var benchmarkColors = []string{
"#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff",
"#800000", "#008000", "#000080", "#808000", "#800080", "#008080",
"#c0c0c0", "#808080", "#000000", "#ffffff",
}
var benchmarkPoints = [][]engine.Point{
// Triangle
{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 0.5, Y: 1}},
// Square
{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 0, Y: 1}},
// Pentagon
{{X: 0.5, Y: 0}, {X: 1, Y: 0.4}, {X: 0.8, Y: 1}, {X: 0.2, Y: 1}, {X: 0, Y: 0.4}},
// Hexagon
{{X: 0.25, Y: 0}, {X: 0.75, Y: 0}, {X: 1, Y: 0.5}, {X: 0.75, Y: 1}, {X: 0.25, Y: 1}, {X: 0, Y: 0.5}},
}
// Benchmark SVG renderer creation
func BenchmarkNewSVGRenderer(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
size := benchmarkSizes[i%len(benchmarkSizes)]
_ = NewSVGRenderer(size)
}
}
// Benchmark SVG shape rendering
func BenchmarkSVGAddPolygon(b *testing.B) {
renderer := NewSVGRenderer(256)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
color := benchmarkColors[i%len(benchmarkColors)]
points := benchmarkPoints[i%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
}
// Benchmark SVG circle rendering
func BenchmarkSVGAddCircle(b *testing.B) {
renderer := NewSVGRenderer(256)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
color := benchmarkColors[i%len(benchmarkColors)]
topLeft := engine.Point{X: 0.25, Y: 0.25}
size := 0.5
renderer.BeginShape(color)
renderer.AddCircle(topLeft, size, false)
renderer.EndShape()
}
}
// Benchmark SVG background setting
func BenchmarkSVGSetBackground(b *testing.B) {
renderer := NewSVGRenderer(256)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
color := benchmarkColors[i%len(benchmarkColors)]
opacity := 0.8
renderer.SetBackground(color, opacity)
}
}
// Benchmark complete SVG generation
func BenchmarkSVGToSVG(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
size := benchmarkSizes[i%len(benchmarkSizes)]
renderer := NewSVGRenderer(size)
// Add some shapes
renderer.SetBackground("#f0f0f0", 1.0)
for j := 0; j < 3; j++ {
color := benchmarkColors[j%len(benchmarkColors)]
points := benchmarkPoints[j%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
_ = renderer.ToSVG()
}
}
// Benchmark PNG renderer creation
func BenchmarkNewPNGRenderer(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
size := benchmarkSizes[i%len(benchmarkSizes)]
_ = NewPNGRenderer(size)
}
}
// Benchmark PNG shape rendering
func BenchmarkPNGAddPolygon(b *testing.B) {
renderer := NewPNGRenderer(256)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
color := benchmarkColors[i%len(benchmarkColors)]
points := benchmarkPoints[i%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
}
// Benchmark PNG circle rendering
func BenchmarkPNGAddCircle(b *testing.B) {
renderer := NewPNGRenderer(256)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
color := benchmarkColors[i%len(benchmarkColors)]
topLeft := engine.Point{X: 0.25, Y: 0.25}
size := 0.5
renderer.BeginShape(color)
renderer.AddCircle(topLeft, size, false)
renderer.EndShape()
}
}
// Benchmark PNG background setting
func BenchmarkPNGSetBackground(b *testing.B) {
renderer := NewPNGRenderer(256)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
color := benchmarkColors[i%len(benchmarkColors)]
opacity := 0.8
renderer.SetBackground(color, opacity)
}
}
// Benchmark complete PNG generation
func BenchmarkPNGToPNG(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
size := benchmarkSizes[i%len(benchmarkSizes)]
renderer := NewPNGRenderer(size)
// Add some shapes
renderer.SetBackground("#f0f0f0", 1.0)
for j := 0; j < 3; j++ {
color := benchmarkColors[j%len(benchmarkColors)]
points := benchmarkPoints[j%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
_, err := renderer.ToPNG()
if err != nil {
b.Fatalf("ToPNG failed: %v", err)
}
}
}
// Benchmark PNG generation with different output sizes
func BenchmarkPNGToPNGWithSize(b *testing.B) {
renderer := NewPNGRenderer(128)
// Add some test shapes
renderer.SetBackground("#ffffff", 1.0)
renderer.BeginShape("#ff0000")
renderer.AddPolygon(benchmarkPoints[0])
renderer.EndShape()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outputSize := benchmarkSizes[i%len(benchmarkSizes)]
_, err := renderer.ToPNGWithSize(outputSize)
if err != nil {
b.Fatalf("ToPNGWithSize failed: %v", err)
}
}
}
// Benchmark complex shape rendering (many polygons)
func BenchmarkComplexSVGRendering(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewSVGRenderer(256)
renderer.SetBackground("#f8f8f8", 1.0)
// Render many shapes to simulate complex icon
for j := 0; j < 12; j++ {
color := benchmarkColors[j%len(benchmarkColors)]
points := benchmarkPoints[j%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
_ = renderer.ToSVG()
}
}
// Benchmark complex shape rendering (many polygons) for PNG
func BenchmarkComplexPNGRendering(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewPNGRenderer(256)
renderer.SetBackground("#f8f8f8", 1.0)
// Render many shapes to simulate complex icon
for j := 0; j < 12; j++ {
color := benchmarkColors[j%len(benchmarkColors)]
points := benchmarkPoints[j%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
_, err := renderer.ToPNG()
if err != nil {
b.Fatalf("ToPNG failed: %v", err)
}
}
}
// Benchmark SVG vs PNG rendering comparison
func BenchmarkSVGvsPNG64px(b *testing.B) {
// Shared test data
testShapes := []struct {
color string
points []engine.Point
}{
{"#ff0000", benchmarkPoints[0]},
{"#00ff00", benchmarkPoints[1]},
{"#0000ff", benchmarkPoints[2]},
}
b.Run("SVG", func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewSVGRenderer(64)
renderer.SetBackground("#ffffff", 1.0)
for _, shape := range testShapes {
renderer.BeginShape(shape.color)
renderer.AddPolygon(shape.points)
renderer.EndShape()
}
_ = renderer.ToSVG()
}
})
b.Run("PNG", func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewPNGRenderer(64)
renderer.SetBackground("#ffffff", 1.0)
for _, shape := range testShapes {
renderer.BeginShape(shape.color)
renderer.AddPolygon(shape.points)
renderer.EndShape()
}
_, err := renderer.ToPNG()
if err != nil {
b.Fatalf("ToPNG failed: %v", err)
}
}
})
}
// Benchmark memory allocation patterns
func BenchmarkRendererMemoryPatterns(b *testing.B) {
b.Run("SVGMemory", func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewSVGRenderer(128)
// Allocate many small shapes to test memory patterns
for j := 0; j < 20; j++ {
renderer.BeginShape("#808080")
renderer.AddPolygon(benchmarkPoints[j%len(benchmarkPoints)])
renderer.EndShape()
}
}
})
b.Run("PNGMemory", func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewPNGRenderer(128)
// Allocate many small shapes to test memory patterns
for j := 0; j < 20; j++ {
renderer.BeginShape("#808080")
renderer.AddPolygon(benchmarkPoints[j%len(benchmarkPoints)])
renderer.EndShape()
}
}
})
}
// Benchmark concurrent rendering scenarios
func BenchmarkRendererParallel(b *testing.B) {
b.Run("SVGParallel", func(b *testing.B) {
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
size := benchmarkSizes[i%len(benchmarkSizes)]
renderer := NewSVGRenderer(size)
renderer.SetBackground("#ffffff", 1.0)
for j := 0; j < 3; j++ {
color := benchmarkColors[j%len(benchmarkColors)]
points := benchmarkPoints[j%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
_ = renderer.ToSVG()
i++
}
})
})
b.Run("PNGParallel", func(b *testing.B) {
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
size := benchmarkSizes[i%len(benchmarkSizes)]
renderer := NewPNGRenderer(size)
renderer.SetBackground("#ffffff", 1.0)
for j := 0; j < 3; j++ {
color := benchmarkColors[j%len(benchmarkColors)]
points := benchmarkPoints[j%len(benchmarkPoints)]
renderer.BeginShape(color)
renderer.AddPolygon(points)
renderer.EndShape()
}
_, err := renderer.ToPNG()
if err != nil {
b.Errorf("ToPNG failed: %v", err)
}
i++
}
})
})
}
// Benchmark shape rendering with different complexities
func BenchmarkShapeComplexity(b *testing.B) {
renderer := NewSVGRenderer(256)
b.Run("Triangle", func(b *testing.B) {
b.ReportAllocs()
trianglePoints := benchmarkPoints[0] // Triangle
for i := 0; i < b.N; i++ {
renderer.BeginShape("#ff0000")
renderer.AddPolygon(trianglePoints)
renderer.EndShape()
}
})
b.Run("Square", func(b *testing.B) {
b.ReportAllocs()
squarePoints := benchmarkPoints[1] // Square
for i := 0; i < b.N; i++ {
renderer.BeginShape("#00ff00")
renderer.AddPolygon(squarePoints)
renderer.EndShape()
}
})
b.Run("Pentagon", func(b *testing.B) {
b.ReportAllocs()
pentagonPoints := benchmarkPoints[2] // Pentagon
for i := 0; i < b.N; i++ {
renderer.BeginShape("#0000ff")
renderer.AddPolygon(pentagonPoints)
renderer.EndShape()
}
})
b.Run("Hexagon", func(b *testing.B) {
b.ReportAllocs()
hexagonPoints := benchmarkPoints[3] // Hexagon
for i := 0; i < b.N; i++ {
renderer.BeginShape("#ffff00")
renderer.AddPolygon(hexagonPoints)
renderer.EndShape()
}
})
}