Files
go-jdenticon/internal/renderer/optimized_bench_test.go
Kevin McIntyre d9e84812ff 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
2026-01-03 23:41:48 -05:00

180 lines
3.8 KiB
Go

package renderer
import (
"fmt"
"testing"
"github.com/ungluedlabs/go-jdenticon/internal/engine"
)
// Benchmark optimized PNG renderer vs original FastPNG renderer
func BenchmarkOptimizedPNGToPNG(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 memory usage with different allocation patterns
func BenchmarkPNGMemoryPatterns(b *testing.B) {
// Shared test data
testShapes := []struct {
color string
points []engine.Point
}{
{"#ff0000", benchmarkPoints[0]},
{"#00ff00", benchmarkPoints[1]},
{"#0000ff", benchmarkPoints[2]},
}
b.Run("OptimizedPNG", func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewPNGRenderer(256)
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)
}
}
})
b.Run("PNGWrapper", func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewPNGRenderer(256)
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 different icon sizes to see memory scaling
func BenchmarkOptimizedPNGSizes(b *testing.B) {
testShapes := []struct {
color string
points []engine.Point
}{
{"#ff0000", benchmarkPoints[0]},
{"#00ff00", benchmarkPoints[1]},
{"#0000ff", benchmarkPoints[2]},
}
sizes := []int{64, 128, 256, 512}
for _, size := range sizes {
b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewPNGRenderer(size)
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 complex shape rendering with optimized renderer
func BenchmarkOptimizedComplexPNGRendering(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 pooling efficiency
func BenchmarkPoolingEfficiency(b *testing.B) {
b.Run("WithPooling", func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
renderer := NewPNGRenderer(128)
renderer.SetBackground("#ffffff", 1.0)
// Add multiple polygons to exercise pooling
for j := 0; j < 10; j++ {
renderer.BeginShape("#808080")
renderer.AddPolygon(benchmarkPoints[j%len(benchmarkPoints)])
renderer.EndShape()
}
_, err := renderer.ToPNG()
if err != nil {
b.Fatalf("ToPNG failed: %v", err)
}
}
})
}