Initial release: Go Jdenticon library v0.1.0
- Core library with SVG and PNG generation - CLI tool with generate and batch commands - Cross-platform path handling for Windows compatibility - Comprehensive test suite with integration tests
This commit is contained in:
464
internal/renderer/renderer_bench_test.go
Normal file
464
internal/renderer/renderer_bench_test.go
Normal file
@@ -0,0 +1,464 @@
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ungluedlabs/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()
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user