mirror of
https://github.com/prometheus/prometheus.git
synced 2026-02-03 20:39:32 -05:00
Merge 62deb32932 into 44d772b4e7
This commit is contained in:
commit
7c4bb45c64
4 changed files with 381 additions and 55 deletions
|
|
@ -4091,6 +4091,10 @@ func PreprocessExpr(expr parser.Expr, start, end time.Time, step time.Duration)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
expr, err := ConstantFoldExpr(expr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, shouldWrap := preprocessExprHelper(expr, start, end)
|
||||
if shouldWrap {
|
||||
return newStepInvariantExpr(expr), nil
|
||||
|
|
|
|||
|
|
@ -3174,61 +3174,6 @@ func TestPreprocessAndWrapWithStepInvariantExpr(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `floor(some_metric / (3 * 1024))`,
|
||||
outputTest: true,
|
||||
expected: &parser.Call{
|
||||
Func: &parser.Function{
|
||||
Name: "floor",
|
||||
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
|
||||
ReturnType: parser.ValueTypeVector,
|
||||
},
|
||||
Args: parser.Expressions{
|
||||
&parser.BinaryExpr{
|
||||
Op: parser.DIV,
|
||||
LHS: &parser.VectorSelector{
|
||||
Name: "some_metric",
|
||||
LabelMatchers: []*labels.Matcher{
|
||||
parser.MustLabelMatcher(labels.MatchEqual, "__name__", "some_metric"),
|
||||
},
|
||||
PosRange: posrange.PositionRange{
|
||||
Start: 6,
|
||||
End: 17,
|
||||
},
|
||||
},
|
||||
RHS: &parser.StepInvariantExpr{
|
||||
Expr: &parser.ParenExpr{
|
||||
Expr: &parser.BinaryExpr{
|
||||
Op: parser.MUL,
|
||||
LHS: &parser.NumberLiteral{
|
||||
Val: 3,
|
||||
PosRange: posrange.PositionRange{
|
||||
Start: 21,
|
||||
End: 22,
|
||||
},
|
||||
},
|
||||
RHS: &parser.NumberLiteral{
|
||||
Val: 1024,
|
||||
PosRange: posrange.PositionRange{
|
||||
Start: 25,
|
||||
End: 29,
|
||||
},
|
||||
},
|
||||
},
|
||||
PosRange: posrange.PositionRange{
|
||||
Start: 20,
|
||||
End: 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PosRange: posrange.PositionRange{
|
||||
Start: 0,
|
||||
End: 31,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
|
|
|||
118
promql/folding.go
Normal file
118
promql/folding.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2025 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package promql
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
)
|
||||
|
||||
func ConstantFoldExpr(expr parser.Expr) (parser.Expr, error) {
|
||||
var err error
|
||||
switch n := expr.(type) {
|
||||
case *parser.BinaryExpr:
|
||||
lhs, err := ConstantFoldExpr(n.LHS)
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
rhs, err := ConstantFoldExpr(n.RHS)
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
n.LHS, n.RHS = lhs, rhs
|
||||
|
||||
unwrapParenExpr(&lhs)
|
||||
unwrapParenExpr(&rhs)
|
||||
|
||||
if lhs.Type() == parser.ValueTypeScalar && rhs.Type() == parser.ValueTypeScalar {
|
||||
lhsVal, okLHS := lhs.(*parser.NumberLiteral)
|
||||
rhsVal, okRHS := rhs.(*parser.NumberLiteral)
|
||||
if okLHS && okRHS {
|
||||
val := scalarBinop(n.Op, lhsVal.Val, rhsVal.Val)
|
||||
return &parser.NumberLiteral{
|
||||
Val: val,
|
||||
PosRange: n.PositionRange(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case *parser.Call:
|
||||
if n.Func.Name == "pi" {
|
||||
return &parser.NumberLiteral{
|
||||
Val: math.Pi,
|
||||
PosRange: n.PositionRange(),
|
||||
}, nil
|
||||
}
|
||||
for i := range n.Args {
|
||||
n.Args[i], err = ConstantFoldExpr(n.Args[i])
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case *parser.MatrixSelector:
|
||||
n.VectorSelector, err = ConstantFoldExpr(n.VectorSelector)
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case *parser.AggregateExpr:
|
||||
n.Expr, err = ConstantFoldExpr(n.Expr)
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case *parser.SubqueryExpr:
|
||||
n.Expr, err = ConstantFoldExpr(n.Expr)
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case *parser.ParenExpr:
|
||||
n.Expr, err = ConstantFoldExpr(n.Expr)
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
return n, nil
|
||||
|
||||
case *parser.UnaryExpr:
|
||||
n.Expr, err = ConstantFoldExpr(n.Expr)
|
||||
if err != nil {
|
||||
return expr, err
|
||||
}
|
||||
|
||||
unwrapParenExpr(&n.Expr)
|
||||
if n.Expr.Type() == parser.ValueTypeScalar {
|
||||
if val, ok := n.Expr.(*parser.NumberLiteral); ok {
|
||||
if n.Op == parser.SUB {
|
||||
val.Val = -val.Val
|
||||
}
|
||||
return &parser.NumberLiteral{
|
||||
Val: val.Val,
|
||||
PosRange: n.PositionRange(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
|
||||
default:
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
259
promql/folding_test.go
Normal file
259
promql/folding_test.go
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
package promql
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/parser/posrange"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testExpr = []struct {
|
||||
input string
|
||||
expected parser.Expr
|
||||
}{
|
||||
{
|
||||
input: "1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "+Inf",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: math.Inf(1),
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 4},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "123.4567",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 123.4567,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 8},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "5e-3",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 0.005,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 4},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 + 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 2,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 5},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "pi()",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: math.Pi,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 4},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 - 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 0,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 5},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 * 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 5},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 % 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 0,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 5},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 / 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 5},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 == bool 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 11},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 != bool 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 0,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 11},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 > bool 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 0,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 10},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 >= bool 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 11},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 < bool 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 0,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 10},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 <= bool 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 11},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "(-1)^2",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 6},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "-1*2",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: -2,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 4},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "-1+2",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 4},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "(-1)^-2",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 7},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "+1 + -2 * 1",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: -1,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 11},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 + 2/(3*1)",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1.6666666666666665,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 11},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 < bool 2 - 1 * 2",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 0,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 18},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "((1+2)*(3-1))/(2+2)",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 1.5,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 19},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "(((-1)^2) + (2 % 3) * (4 - 1))",
|
||||
expected: &parser.ParenExpr{
|
||||
Expr: &parser.NumberLiteral{
|
||||
Val: 7,
|
||||
PosRange: posrange.PositionRange{Start: 1, End: 29},
|
||||
},
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 30},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "-(1 + 2) * +((3 - 5) ^ 2)",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: -12,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 24},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "((1+1) == bool (2))",
|
||||
expected: &parser.ParenExpr{
|
||||
Expr: &parser.NumberLiteral{
|
||||
Val: 1,
|
||||
PosRange: posrange.PositionRange{Start: 1, End: 18},
|
||||
},
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 19},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "((1+2) <= bool (2-1))",
|
||||
expected: &parser.ParenExpr{
|
||||
Expr: &parser.NumberLiteral{
|
||||
Val: 0,
|
||||
PosRange: posrange.PositionRange{Start: 1, End: 20},
|
||||
},
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 21},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "1 + 2/(3*1) + (4-2)*(7%5)",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 5.666666666666666,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 25},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "pi() * (1 + 1) - (3 - 3)",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 2 * math.Pi,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 24},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "((1.5 + 2.25) * 2) / (7 - 3)",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: ((1.5 + 2.25) * 2) / 4,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 28},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "((1 < bool 2) + (3 == bool 3)) * (4 % 3)",
|
||||
expected: &parser.NumberLiteral{
|
||||
Val: 2,
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 40},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestConstantFolding(t *testing.T) {
|
||||
for _, test := range testExpr {
|
||||
expr, err := parser.ParseExpr(test.input)
|
||||
require.NoError(t, err, "cannot parse original query")
|
||||
expr, err = ConstantFoldExpr(expr)
|
||||
require.NoError(t, err, "cannot fold query")
|
||||
require.Equal(t, test.expected, expr, "error on input '%s'", test.input)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue