Skip to content

Commit

Permalink
header.go Referer() optimize (valyala#1313)
Browse files Browse the repository at this point in the history
* args.go GetBool(): use switch with string casting

This should be optimized by Go compiler itself so the b2s() call is not needed.

It was previously done by this but changed in
1e7885e

* header.go Referer() optimize

Use direct peekArgBytes() instead of PeekBytes() that will check for special headers

* header_timing_test.go BenchmarkRequestHeaderPeekBytesSpecialHeader

The old BenchmarkRequestHeaderPeekBytesCanonical and BenchmarkRequestHeaderPeekBytesNonCanonical are in fact just measured the header normalization.
But it's anyway is benchmarked separately.
Results was almost the same: 1.5 ns/op.

Instead, let's reuse the benches to find a difference between peeking of special (Host, CT) and custom headers.
  • Loading branch information
stokito authored and bbenzikry committed Sep 11, 2022
1 parent 1626dde commit 76ff02a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 9 deletions.
2 changes: 1 addition & 1 deletion args.go
Expand Up @@ -343,7 +343,7 @@ func (a *Args) GetUfloatOrZero(key string) float64 {
// true is returned for "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes",
// otherwise false is returned.
func (a *Args) GetBool(key string) bool {
switch b2s(a.Peek(key)) {
switch string(a.Peek(key)) {
// Support the same true cases as strconv.ParseBool
// See: https://github.com/golang/go/blob/4e1b11e2c9bdb0ddea1141eed487be1a626ff5be/src/strconv/atob.go#L12
// and Y and Yes versions.
Expand Down
2 changes: 1 addition & 1 deletion header.go
Expand Up @@ -586,7 +586,7 @@ func (h *RequestHeader) SetUserAgentBytes(userAgent []byte) {

// Referer returns Referer header value.
func (h *RequestHeader) Referer() []byte {
return h.PeekBytes(strReferer)
return peekArgBytes(h.h, strReferer)
}

// SetReferer sets Referer header value.
Expand Down
46 changes: 39 additions & 7 deletions header_timing_test.go
Expand Up @@ -12,6 +12,9 @@ import (

var strFoobar = []byte("foobar.com")

// it has the same length as Content-Type
var strNonSpecialHeader = []byte("Dontent-Type")

type benchReadBuf struct {
s []byte
n int
Expand Down Expand Up @@ -96,26 +99,55 @@ func BenchmarkResponseHeaderWrite(b *testing.B) {
})
}

func BenchmarkRequestHeaderPeekBytesCanonical(b *testing.B) {
// Result: 2.2 ns/op
func BenchmarkRequestHeaderPeekBytesSpecialHeader(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var h RequestHeader
h.SetBytesV("Host", strFoobar)
h.SetContentTypeBytes(strFoobar)
for pb.Next() {
v := h.PeekBytes(strHost)
v := h.PeekBytes(strContentType)
if !bytes.Equal(v, strFoobar) {
b.Fatalf("unexpected result: %q. Expected %q", v, strFoobar)
}
}
})
}

func BenchmarkRequestHeaderPeekBytesNonCanonical(b *testing.B) {
// Result: 2.9 ns/op
func BenchmarkRequestHeaderPeekBytesNonSpecialHeader(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var h RequestHeader
h.SetBytesV("Host", strFoobar)
hostBytes := []byte("HOST")
h.SetBytesKV(strNonSpecialHeader, strFoobar)
for pb.Next() {
v := h.PeekBytes(strNonSpecialHeader)
if !bytes.Equal(v, strFoobar) {
b.Fatalf("unexpected result: %q. Expected %q", v, strFoobar)
}
}
})
}

// Result: 2.3 ns/op
func BenchmarkResponseHeaderPeekBytesSpecialHeader(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var h ResponseHeader
h.SetContentTypeBytes(strFoobar)
for pb.Next() {
v := h.PeekBytes(strContentType)
if !bytes.Equal(v, strFoobar) {
b.Fatalf("unexpected result: %q. Expected %q", v, strFoobar)
}
}
})
}

// Result: 2.9 ns/op
func BenchmarkResponseHeaderPeekBytesNonSpecialHeader(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var h ResponseHeader
h.SetBytesKV(strNonSpecialHeader, strFoobar)
for pb.Next() {
v := h.PeekBytes(hostBytes)
v := h.PeekBytes(strNonSpecialHeader)
if !bytes.Equal(v, strFoobar) {
b.Fatalf("unexpected result: %q. Expected %q", v, strFoobar)
}
Expand Down

0 comments on commit 76ff02a

Please sign in to comment.