Files
sux/performance_test.go

200 lines
4.5 KiB
Go
Raw Normal View History

package sux
import (
"net/http"
"net/http/httptest"
"runtime"
"testing"
)
// BenchmarkParameterOperations benchmarks the new parameter handling
func BenchmarkParameterOperations(b *testing.B) {
params := Params{
keys: make([]string, 0, 4),
values: make([]string, 0, 4),
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
params.Set("id", "123")
params.Set("name", "test")
_ = params.Get("id")
_ = params.Get("name")
params.Reset()
}
}
// BenchmarkPathParsing compares old vs new path parsing
func BenchmarkPathParsingOld(b *testing.B) {
path := "/users/123/posts/456/comments/789"
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = parsePath(path)
}
}
func BenchmarkPathParsingNew(b *testing.B) {
path := "/users/123/posts/456/comments/789"
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = parsePathZeroAlloc(path)
}
}
// BenchmarkMemoryUsage tests memory efficiency under load
func BenchmarkMemoryUsage(b *testing.B) {
router := New()
// Add routes with different patterns
router.GET("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
router.GET("/users/:id", func(w http.ResponseWriter, r *http.Request) {
params := ParamsFromContext(r)
_ = params.Get("id")
w.WriteHeader(http.StatusOK)
})
router.GET("/files/*path", func(w http.ResponseWriter, r *http.Request) {
params := ParamsFromContext(r)
_ = params.Get("path")
w.WriteHeader(http.StatusOK)
})
requests := []struct {
method string
path string
}{
{"GET", "/"},
{"GET", "/users/123"},
{"GET", "/files/docs/readme.txt"},
}
var reqs []*http.Request
for _, req := range requests {
for i := 0; i < 100; i++ {
reqs = append(reqs, httptest.NewRequest(req.method, req.path, nil))
}
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
w := httptest.NewRecorder()
router.ServeHTTP(w, reqs[i%len(reqs)])
}
}
// BenchmarkConcurrentAccess tests performance under high concurrency
func BenchmarkConcurrentAccess(b *testing.B) {
router := New()
router.GET("/test/:id", func(w http.ResponseWriter, r *http.Request) {
params := ParamsFromContext(r)
_ = params.Get("id")
w.WriteHeader(http.StatusOK)
})
req := httptest.NewRequest("GET", "/test/123", nil)
b.ResetTimer()
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
}
})
}
// BenchmarkGCPressure measures GC pressure from allocations
func BenchmarkGCPressure(b *testing.B) {
router := New()
router.GET("/users/:id/posts/:postId", func(w http.ResponseWriter, r *http.Request) {
params := ParamsFromContext(r)
_ = params.Get("id") + params.Get("postId")
w.WriteHeader(http.StatusOK)
})
req := httptest.NewRequest("GET", "/users/123/posts/456", nil)
// Force GC before benchmark
runtime.GC()
var m1, m2 runtime.MemStats
runtime.ReadMemStats(&m1)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
}
b.StopTimer()
runtime.ReadMemStats(&m2)
b.Logf("Allocs: %d, TotalAlloc: %d bytes", m2.Mallocs-m1.Mallocs, m2.TotalAlloc-m1.TotalAlloc)
}
// BenchmarkWildcardOptimization tests the wildcard parameter optimization
func BenchmarkWildcardOptimization(b *testing.B) {
router := New()
router.GET("/files/*path", func(w http.ResponseWriter, r *http.Request) {
params := ParamsFromContext(r)
_ = params.Get("path")
w.WriteHeader(http.StatusOK)
})
// Test with varying path lengths
paths := []string{
"/files/file.txt",
"/files/docs/readme.txt",
"/files/docs/api/v1/users.json",
"/files/very/deep/nested/path/with/many/segments/file.txt",
}
var reqs []*http.Request
for _, path := range paths {
for i := 0; i < 25; i++ {
reqs = append(reqs, httptest.NewRequest("GET", path, nil))
}
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
w := httptest.NewRecorder()
router.ServeHTTP(w, reqs[i%len(reqs)])
}
}
// BenchmarkPoolEfficiency tests the efficiency of our pooling strategy
func BenchmarkPoolEfficiency(b *testing.B) {
router := New()
router.GET("/test/:param", func(w http.ResponseWriter, r *http.Request) {
params := ParamsFromContext(r)
_ = params.Get("param")
w.WriteHeader(http.StatusOK)
})
req := httptest.NewRequest("GET", "/test/value", nil)
b.ResetTimer()
b.ReportAllocs()
// This should show minimal allocations due to pooling
for i := 0; i < b.N; i++ {
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
}
}