Files
lneto/http/httphi/zz_scratch_bench_test.go
T
Patricio Whittingslow d83da243a0 add query handling
2026-07-26 13:57:18 -03:00

146 lines
3.5 KiB
Go

package httphi
import "testing"
// Scratch benchmarks isolating query handling. Delete after diagnosis.
const scratchRequest = "GET /?abc=123 HTTP/1.1\r\nHost: tinygo.org\r\nUser-Agent: bench\r\nAccept: */*\r\nConnection: close\r\n\r\n"
func scratchExchange(b *testing.B) (*Exchange, *benchConn, *MuxSlice) {
b.Helper()
conn := &benchConn{request: scratchRequest}
exch := benchExchange(b, conn)
mux := new(MuxSlice)
return exch, conn, mux
}
// A: whole exchange, handler writes body only. No query touched.
func BenchmarkScratchBodyOnly(b *testing.B) {
exch, conn, mux := scratchExchange(b)
mux.Handle("GET /", func(ex *Exchange) { ex.Write(benchBody) })
b.ReportAllocs()
for i := 0; i < b.N; i++ {
conn.rewind()
exch.Release()
exch.Acquire(conn)
Handle(exch, mux, nopBackoff)
}
}
// B: same plus header writes. Isolates SetHeader/SetHeaderInt.
func BenchmarkScratchHeaders(b *testing.B) {
exch, conn, mux := scratchExchange(b)
mux.Handle("GET /", func(ex *Exchange) {
ex.SetHeader("Content-Type", "text/plain")
ex.SetHeaderInt("Content-Length", int64(len(benchBody)), 10)
ex.Write(benchBody)
})
b.ReportAllocs()
for i := 0; i < b.N; i++ {
conn.rewind()
exch.Release()
exch.Acquire(conn)
Handle(exch, mux, nopBackoff)
}
}
// C: iteration only, closure captures one counter.
func BenchmarkScratchForEachQuery(b *testing.B) {
exch, conn, mux := scratchExchange(b)
var seen int
mux.Handle("GET /", func(ex *Exchange) {
ex.ForEachQueryRaw(func(rawkey, rawval []byte) bool {
seen += len(rawkey)
return true
})
})
b.ReportAllocs()
for i := 0; i < b.N; i++ {
conn.rewind()
exch.Release()
exch.Acquire(conn)
Handle(exch, mux, nopBackoff)
}
_ = seen
}
// C2: closure that reassigns a captured slice, exactly AppendQuery's shape.
func BenchmarkScratchClosureSlice(b *testing.B) {
exch, conn, mux := scratchExchange(b)
buf := make([]byte, 64)
mux.Handle("GET /", func(ex *Exchange) {
out := buf[:0]
found := false
ex.ForEachQueryRaw(func(rawkey, rawval []byte) bool {
if b2s(rawkey) != "abc" {
return true
}
out = append(out, rawval...)
found = true
return false
})
_ = found
_ = out
})
b.ReportAllocs()
for i := 0; i < b.N; i++ {
conn.rewind()
exch.Release()
exch.Acquire(conn)
Handle(exch, mux, nopBackoff)
}
}
// C3: same but the captured slice is only read, never reassigned.
func BenchmarkScratchClosureNoReassign(b *testing.B) {
exch, conn, mux := scratchExchange(b)
buf := make([]byte, 64)
mux.Handle("GET /", func(ex *Exchange) {
n := 0
ex.ForEachQueryRaw(func(rawkey, rawval []byte) bool {
n += copy(buf, rawval)
return false
})
_ = n
})
b.ReportAllocs()
for i := 0; i < b.N; i++ {
conn.rewind()
exch.Release()
exch.Acquire(conn)
Handle(exch, mux, nopBackoff)
}
}
// D: AppendQuery raw, into a buffer with capacity.
func BenchmarkScratchAppendQueryRaw(b *testing.B) {
exch, conn, mux := scratchExchange(b)
buf := make([]byte, 64)
mux.Handle("GET /", func(ex *Exchange) {
ex.AppendQuery(buf[:0], "abc", false)
})
b.ReportAllocs()
for i := 0; i < b.N; i++ {
conn.rewind()
exch.Release()
exch.Acquire(conn)
Handle(exch, mux, nopBackoff)
}
}
// E: AppendQuery decoded.
func BenchmarkScratchAppendQueryDecoded(b *testing.B) {
exch, conn, mux := scratchExchange(b)
buf := make([]byte, 64)
mux.Handle("GET /", func(ex *Exchange) {
ex.AppendQuery(buf[:0], "abc", true)
})
b.ReportAllocs()
for i := 0; i < b.N; i++ {
conn.rewind()
exch.Release()
exch.Acquire(conn)
Handle(exch, mux, nopBackoff)
}
}