From cd6a5d4a0b1abe2587a0d8c79d43104bce985f30 Mon Sep 17 00:00:00 2001 From: Cyril Tovena Date: Fri, 4 Nov 2022 02:16:13 -0400 Subject: [PATCH] Improves performance of json responses (#7522) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **What this PR does / why we need it**: This allows to reuse stream memory allocations between responses. Related https://github.com/grafana/loki/pull/3163 but this time this is for the encoding. ``` ❯ benchstat before.txt after.txt name old time/op new time/op delta _Encode-16 29.2µs ±12% 25.2µs ± 1% -13.85% (p=0.016 n=5+4) name old alloc/op new alloc/op delta _Encode-16 24.9kB ± 6% 16.4kB ± 8% -34.20% (p=0.008 n=5+5) name old allocs/op new allocs/op delta _Encode-16 145 ± 0% 129 ± 0% -11.03% (p=0.008 n=5+5) ``` --- pkg/util/marshal/marshal.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/pkg/util/marshal/marshal.go b/pkg/util/marshal/marshal.go index 3fbdb84dbdbc3..9e533e9ace91c 100644 --- a/pkg/util/marshal/marshal.go +++ b/pkg/util/marshal/marshal.go @@ -32,7 +32,11 @@ func WriteQueryResponseJSON(v logqlmodel.Result, w io.Writer) error { }, } - return jsoniter.NewEncoder(w).Encode(q) + s := jsoniter.ConfigFastest.BorrowStream(w) + defer jsoniter.ConfigFastest.ReturnStream(s) + s.WriteVal(q) + s.WriteRaw("\n") + return s.Flush() } // WriteLabelResponseJSON marshals a logproto.LabelResponse to v1 loghttp JSON @@ -43,7 +47,11 @@ func WriteLabelResponseJSON(l logproto.LabelResponse, w io.Writer) error { Data: l.GetValues(), } - return jsoniter.NewEncoder(w).Encode(v1Response) + s := jsoniter.ConfigFastest.BorrowStream(w) + defer jsoniter.ConfigFastest.ReturnStream(s) + s.WriteVal(v1Response) + s.WriteRaw("\n") + return s.Flush() } // WebsocketWriter knows how to write message to a websocket connection. @@ -77,7 +85,11 @@ func WriteSeriesResponseJSON(r logproto.SeriesResponse, w io.Writer) error { adapter.Data = append(adapter.Data, series.GetLabels()) } - return jsoniter.NewEncoder(w).Encode(adapter) + s := jsoniter.ConfigFastest.BorrowStream(w) + defer jsoniter.ConfigFastest.ReturnStream(s) + s.WriteVal(adapter) + s.WriteRaw("\n") + return s.Flush() } // This struct exists primarily because we can't specify a repeated map in proto v3. @@ -90,5 +102,9 @@ type seriesResponseAdapter struct { // WriteIndexStatsResponseJSON marshals a gatewaypb.Stats to JSON and then // writes it to the provided io.Writer. func WriteIndexStatsResponseJSON(r *stats.Stats, w io.Writer) error { - return jsoniter.NewEncoder(w).Encode(r) + s := jsoniter.ConfigFastest.BorrowStream(w) + defer jsoniter.ConfigFastest.ReturnStream(s) + s.WriteVal(r) + s.WriteRaw("\n") + return s.Flush() }