Skip to content

Commit

Permalink
eskip: add BenchmarkJsonUnmarshal (#2876)
Browse files Browse the repository at this point in the history
Add a benchmark of unmarshalling 10000 routes from JSON and
compare its performance to eskip parsing.

This establishes a baseline for future optimizations.

```
$ benchstat -col .name <(go test ./eskip -run=NONE -bench='BenchmarkJsonUnmarshal|BenchmarkParse$' -count=10)
goos: linux
goarch: amd64
pkg: github.com/zalando/skipper/eskip
    │    Parse    │             JsonUnmarshal              │
    │   sec/op    │    sec/op      vs base                 │
*-8   247.1m ± 1%   1281.4m ± 16%  +418.51% (p=0.000 n=10)

    │    Parse     │            JsonUnmarshal            │
    │     B/op     │     B/op      vs base               │
*-8   49.02Mi ± 0%   46.54Mi ± 0%  -5.06% (p=0.000 n=10)

    │    Parse    │            JsonUnmarshal            │
    │  allocs/op  │  allocs/op   vs base                │
*-8   1.080M ± 0%   1.420M ± 0%  +31.48% (p=0.000 n=10)
```

Signed-off-by: Alexander Yastrebov <[email protected]>
  • Loading branch information
AlexanderYastrebov authored Jan 19, 2024
1 parent 4a0606a commit acacf3e
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 22 deletions.
44 changes: 22 additions & 22 deletions eskip/eskip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,26 @@ import (
"github.com/stretchr/testify/assert"
)

var benchmarkRoutes10k = strings.Repeat(`xxxx_xx__xxxxx__xxx_xxxxxxxx_xxxxxxxxxx_xxxxxxx_xxxxxxx_xxxxxxx_xxxxx__xxx__40_0:
Path("/xxxxxxxxx/:xxxxxxxx_xx/xxxxxxxx-xxxxxxxxxx-xxxxxxxxx")
&& Host("^(xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-18[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-19[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-20[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-21[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxxxxxxxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx[.]xxxxxxxxxxx[.]xxx[.]?(:[0-9]+)?)$")
&& Host("^(xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-21[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?)$")
&& Weight(4)
&& Method("GET")
&& JWTPayloadAllKV("xxxxx://xxxxxxxx.xxxxxxx.xxx/xxxxx", "xxxxx")
&& Header("X-Xxxxxxxxx-Xxxxx", "xxxxx")
-> disableAccessLog(2, 3, 40, 500)
-> fifo(1000, 100, "10s")
-> apiUsageMonitoring("{\"xxx_xx\":\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\"xxxxxxxxxxx_xx\":\"xxx-xxxxxxxx-xxxxxxxxxx\",\"xxxx_xxxxxxxxx\":[\"/xxxxxxxxx/{xxxxxxxx_xx}/xxxxxxxx-xxxxxxxxxx\",\"/xxxxxxxxx/{xxxxxxxx_xx}/xxxxxxxx-xxxxxxxxxx-xxxxxxx\",\"/xxxxxxxxx/{xxxxxxxx_xx}/xxxxxxxx-xxxxxxxxxx-xxxxxxxxx\"]}")
-> oauthTokeninfoAnyKV("xxxxx", "/xxxxxxxxx")
-> unverifiedAuditLog("xxxxx://xxxxxxxx.xxxxxxx.xxx/xxxxxxx-xx")
-> oauthTokeninfoAllScope("xxx")
-> flowId("reuse")
-> forwardToken("X-XxxxxXxxx-Xxxxxxx", "xxx", "xxxxx", "xxxxx")
-> stateBagToTag("xxxx-xxxx", "xxxxxx.xxx")
-> <powerOfRandomNChoices, "http://1.2.1.1:8080", "http://1.2.1.2:8080", "http://1.2.1.3:8080", "http://1.2.1.4:8080", "http://1.2.1.5:8080">;
`, 10_000)

func TestParse(t *testing.T) {
for _, ti := range []struct {
msg string
Expand Down Expand Up @@ -741,35 +761,15 @@ func BenchmarkParsePredicates(b *testing.B) {
}

func BenchmarkParse(b *testing.B) {
doc := strings.Repeat(`xxxx_xx__xxxxx__xxx_xxxxxxxx_xxxxxxxxxx_xxxxxxx_xxxxxxx_xxxxxxx_xxxxx__xxx__40_0:
Path("/xxxxxxxxx/:xxxxxxxx_xx/xxxxxxxx-xxxxxxxxxx-xxxxxxxxx")
&& Host("^(xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-18[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-19[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-20[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-21[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?|xxxxxxxxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx[.]xxxxxxxxxxx[.]xxx[.]?(:[0-9]+)?)$")
&& Host("^(xxx-xxxxxxxx-xxxxxxxxxx-xxxxxxx-xxxxxxx-xxxx-21[.]xxx-xxxx[.]xxxxx[.]xx[.]?(:[0-9]+)?)$")
&& Weight(4)
&& Method("GET")
&& JWTPayloadAllKV("xxxxx://xxxxxxxx.xxxxxxx.xxx/xxxxx", "xxxxx")
&& Header("X-Xxxxxxxxx-Xxxxx", "xxxxx")
-> disableAccessLog(2, 3, 40, 500)
-> fifo(1000, 100, "10s")
-> apiUsageMonitoring("{\"xxx_xx\":\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\"xxxxxxxxxxx_xx\":\"xxx-xxxxxxxx-xxxxxxxxxx\",\"xxxx_xxxxxxxxx\":[\"/xxxxxxxxx/{xxxxxxxx_xx}/xxxxxxxx-xxxxxxxxxx\",\"/xxxxxxxxx/{xxxxxxxx_xx}/xxxxxxxx-xxxxxxxxxx-xxxxxxx\",\"/xxxxxxxxx/{xxxxxxxx_xx}/xxxxxxxx-xxxxxxxxxx-xxxxxxxxx\"]}")
-> oauthTokeninfoAnyKV("xxxxx", "/xxxxxxxxx")
-> unverifiedAuditLog("xxxxx://xxxxxxxx.xxxxxxx.xxx/xxxxxxx-xx")
-> oauthTokeninfoAllScope("xxx")
-> flowId("reuse")
-> forwardToken("X-XxxxxXxxx-Xxxxxxx", "xxx", "xxxxx", "xxxxx")
-> stateBagToTag("xxxx-xxxx", "xxxxxx.xxx")
-> <powerOfRandomNChoices, "http://1.2.1.1:8080", "http://1.2.1.2:8080", "http://1.2.1.3:8080", "http://1.2.1.4:8080", "http://1.2.1.5:8080">;
`, 10_000)

_, err := Parse(doc)
_, err := Parse(benchmarkRoutes10k)
if err != nil {
b.Fatal(err)
}

b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = Parse(doc)
_, _ = Parse(benchmarkRoutes10k)
}
}

Expand Down
22 changes: 22 additions & 0 deletions eskip/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,25 @@ func TestInvalidJSON(t *testing.T) {
})
}
}

type testRouteContainer struct {
Routes []*Route `json:"routes"`
}

func BenchmarkJsonUnmarshal(b *testing.B) {
content, err := json.Marshal(testRouteContainer{Routes: MustParse(benchmarkRoutes10k)})
if err != nil {
b.Fatal(err)
}

out := testRouteContainer{}
if err := json.Unmarshal(content, &out); err != nil {
b.Fatal(err)
}

b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = json.Unmarshal(content, &out)
}
}

0 comments on commit acacf3e

Please sign in to comment.