mirror of
https://github.com/soypat/lneto.git
synced 2026-08-11 02:13:44 +00:00
146 lines
3.5 KiB
Go
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)
|
|
}
|
|
}
|