From acacf3e047a8f02440fc7fb19977bb430fdedce4 Mon Sep 17 00:00:00 2001 From: Alexander Yastrebov Date: Fri, 19 Jan 2024 15:13:42 +0100 Subject: [PATCH] eskip: add BenchmarkJsonUnmarshal (#2876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- eskip/eskip_test.go | 44 ++++++++++++++++++++++---------------------- eskip/json_test.go | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/eskip/eskip_test.go b/eskip/eskip_test.go index 2324285276..e675e7372b 100644 --- a/eskip/eskip_test.go +++ b/eskip/eskip_test.go @@ -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") +-> ; +`, 10_000) + func TestParse(t *testing.T) { for _, ti := range []struct { msg string @@ -741,27 +761,7 @@ 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") - -> ; - `, 10_000) - - _, err := Parse(doc) + _, err := Parse(benchmarkRoutes10k) if err != nil { b.Fatal(err) } @@ -769,7 +769,7 @@ func BenchmarkParse(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - _, _ = Parse(doc) + _, _ = Parse(benchmarkRoutes10k) } } diff --git a/eskip/json_test.go b/eskip/json_test.go index 698252b1a3..ec7e4f545c 100644 --- a/eskip/json_test.go +++ b/eskip/json_test.go @@ -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) + } +}