From 6534ce843f8765d42ac52ca9c7719a1d5ec27941 Mon Sep 17 00:00:00 2001 From: Tobias Guggenmos Date: Thu, 9 Jan 2020 18:36:13 +0100 Subject: [PATCH] PromQL: Use a sync.Pool for the generated parser structure (#6591) * PromQL: Use a sync.Pool for the generated parser structure The generated PromQL parser allocates a struct about 4kb in size on every run. This puts a high load on the garbage collector. To reduce that load, a sync.Pool is used to recycle these structures. On small queries this makes parsing 2-3 times faster. Signed-off-by: Tobias Guggenmos --- promql/parse.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/promql/parse.go b/promql/parse.go index 07feac875..c9d9af408 100644 --- a/promql/parse.go +++ b/promql/parse.go @@ -19,6 +19,7 @@ import ( "runtime" "strconv" "strings" + "sync" "time" "github.com/pkg/errors" @@ -28,8 +29,14 @@ import ( "github.com/prometheus/prometheus/util/strutil" ) +var parserPool = sync.Pool{ + New: func() interface{} { + return &parser{} + }, +} + type parser struct { - lex *Lexer + lex Lexer inject ItemType injecting bool @@ -54,7 +61,7 @@ func (e *ParseErr) Error() string { // ParseExpr returns the expression parsed from the input. func ParseExpr(input string) (expr Expr, err error) { p := newParser(input) - + defer parserPool.Put(p) defer p.recover(&err) expr = p.parseGenerated(START_EXPRESSION).(Expr) @@ -66,6 +73,7 @@ func ParseExpr(input string) (expr Expr, err error) { // ParseMetric parses the input into a metric func ParseMetric(input string) (m labels.Labels, err error) { p := newParser(input) + defer parserPool.Put(p) defer p.recover(&err) return p.parseGenerated(START_METRIC).(labels.Labels), nil @@ -75,6 +83,7 @@ func ParseMetric(input string) (m labels.Labels, err error) { // label matchers. func ParseMetricSelector(input string) (m []*labels.Matcher, err error) { p := newParser(input) + defer parserPool.Put(p) defer p.recover(&err) return p.parseGenerated(START_METRIC_SELECTOR).(*VectorSelector).LabelMatchers, nil @@ -82,8 +91,14 @@ func ParseMetricSelector(input string) (m []*labels.Matcher, err error) { // newParser returns a new parser. func newParser(input string) *parser { - p := &parser{ - lex: Lex(input), + p := parserPool.Get().(*parser) + + p.injecting = false + + // Clear lexer struct before reusing. + p.lex = Lexer{ + input: input, + state: lexStatements, } return p } @@ -112,6 +127,7 @@ func parseSeriesDesc(input string) (labels labels.Labels, values []sequenceValue p := newParser(input) p.lex.seriesDesc = true + defer parserPool.Put(p) defer p.recover(&err) result := p.parseGenerated(START_SERIES_DESCRIPTION).(*seriesDescription)