github.com/go-graphite/carbonapi@v0.17.0/expr/functions/aggregateWithWildcards/function_test.go (about)

     1  package aggregateWithWildcards
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/go-graphite/carbonapi/expr/interfaces"
    10  	"github.com/go-graphite/carbonapi/expr/metadata"
    11  	"github.com/go-graphite/carbonapi/expr/types"
    12  	"github.com/go-graphite/carbonapi/pkg/parser"
    13  	th "github.com/go-graphite/carbonapi/tests"
    14  )
    15  
    16  var (
    17  	md []interfaces.FunctionMetadata = New("")
    18  )
    19  
    20  func init() {
    21  	for _, m := range md {
    22  		metadata.RegisterFunction(m.Name, m.F)
    23  	}
    24  }
    25  
    26  func TestAggregateWithWildcards(t *testing.T) {
    27  	now32 := int64(time.Now().Unix())
    28  
    29  	tests := []th.EvalTestItem{
    30  		{
    31  			`aggregateWithWildcards(metric[123],"avg",0)`,
    32  			map[parser.MetricRequest][]*types.MetricData{
    33  				{Metric: "metric[123]", From: 0, Until: 1}: {
    34  					types.MakeMetricData("metric1.foo.bar.baz", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32),
    35  					types.MakeMetricData("metric2.foo.bar.baz", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32),
    36  					types.MakeMetricData("metric3.foo.bar.baz", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
    37  				},
    38  			},
    39  			[]*types.MetricData{types.MakeMetricData("foo.bar.baz",
    40  				[]float64{2, math.NaN(), 3, 4, 5, 5.5}, 1, now32).SetNameTag(`metric[123]`).SetTag("aggregatedBy", "avg")},
    41  		},
    42  		{
    43  			`aggregateWithWildcards(metric[123],"diff",1)`,
    44  			map[parser.MetricRequest][]*types.MetricData{
    45  				{Metric: "metric[123]", From: 0, Until: 1}: {
    46  					types.MakeMetricData("metric1.foo.bar.baz", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32),
    47  					types.MakeMetricData("metric1.foo2.bar.baz", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32),
    48  					types.MakeMetricData("metric2.foo.bar.baz", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
    49  				},
    50  			},
    51  			[]*types.MetricData{
    52  				types.MakeMetricData("metric1.bar.baz", []float64{-1, math.NaN(), -1, 3, -1, -1}, 1, now32).SetNameTag(`metric[123]`).SetTag("aggregatedBy", "diff"),
    53  				types.MakeMetricData("metric2.bar.baz", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32).SetNameTag(`metric[123]`).SetTag("aggregatedBy", "diff"),
    54  			},
    55  		},
    56  		{
    57  			`aggregateWithWildcards(metric[1234],"max",2)`,
    58  			map[parser.MetricRequest][]*types.MetricData{
    59  				{Metric: "metric[1234]", From: 0, Until: 1}: {
    60  					types.MakeMetricData("metric1.foo.bar1.baz1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32),
    61  					types.MakeMetricData("metric1.foo.bar2.baz2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32),
    62  					types.MakeMetricData("metric1.foo.bar3.baz1", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
    63  					types.MakeMetricData("metric1.foo.bar4.baz2", []float64{4, math.NaN(), 5, 6, 7, math.NaN()}, 1, now32),
    64  				},
    65  			},
    66  			[]*types.MetricData{
    67  				types.MakeMetricData("metric1.foo.baz1", []float64{3, math.NaN(), 4, 5, 6, 5}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "max"),
    68  				types.MakeMetricData("metric1.foo.baz2", []float64{4, math.NaN(), 5, 6, 7, 6}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "max"),
    69  			},
    70  		},
    71  		{
    72  			`aggregateWithWildcards(metric[1234],"min",3)`,
    73  			map[parser.MetricRequest][]*types.MetricData{
    74  				{Metric: "metric[1234]", From: 0, Until: 1}: {
    75  					types.MakeMetricData("metric1.foo.bar.baz1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32),
    76  					types.MakeMetricData("metric1.foo.bar.baz2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32),
    77  					types.MakeMetricData("metric2.foo.bar.baz3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
    78  					types.MakeMetricData("metric2.foo.bar.baz4", []float64{4, math.NaN(), 5, 6, 7, math.NaN()}, 1, now32),
    79  				},
    80  			},
    81  			[]*types.MetricData{
    82  				types.MakeMetricData("metric1.foo.bar", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "min"),
    83  				types.MakeMetricData("metric2.foo.bar", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "min"),
    84  			},
    85  		},
    86  		{
    87  			`aggregateWithWildcards(metric[1234],"median",0,3)`,
    88  			map[parser.MetricRequest][]*types.MetricData{
    89  				{Metric: "metric[1234]", From: 0, Until: 1}: {
    90  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32),
    91  					types.MakeMetricData("metric2.foo.bar1.baz", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32),
    92  					types.MakeMetricData("metric3.foo.bar2.baz", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
    93  					types.MakeMetricData("metric2.foo.bar2.baz", []float64{4, math.NaN(), 5, 6, 7, 8}, 1, now32),
    94  				},
    95  			},
    96  			[]*types.MetricData{
    97  				types.MakeMetricData("foo.bar1", []float64{1.5, math.NaN(), 2.5, 3, 4.5, 5.5}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "median"),
    98  				types.MakeMetricData("foo.bar2", []float64{3.5, math.NaN(), 4.5, 5.5, 6.5, 8}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "median"),
    99  			},
   100  		},
   101  		{
   102  			`aggregateWithWildcards(metric[1234],"multiply",1,2)`,
   103  			map[parser.MetricRequest][]*types.MetricData{
   104  				{Metric: "metric[1234]", From: 0, Until: 1}: {
   105  					types.MakeMetricData("metric1.foo1.bar.baz", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32),
   106  					types.MakeMetricData("metric1.foo2.bar.baz", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32),
   107  					types.MakeMetricData("metric1.foo3.bar.qux", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
   108  					types.MakeMetricData("metric1.foo4.bar.qux", []float64{4, math.NaN(), 5, 6, 7, math.NaN()}, 1, now32),
   109  				},
   110  			},
   111  			[]*types.MetricData{
   112  				types.MakeMetricData("metric1.baz", []float64{2, math.NaN(), 6, math.NaN(), 20, 30}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "multiply"),
   113  				types.MakeMetricData("metric1.qux", []float64{12, math.NaN(), 20, 30, 42, math.NaN()}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "multiply"),
   114  			},
   115  		},
   116  		{
   117  			`aggregateWithWildcards(metric[1234],"range",0,2)`,
   118  			map[parser.MetricRequest][]*types.MetricData{
   119  				{Metric: "metric[1234]", From: 0, Until: 1}: {
   120  					types.MakeMetricData("metric1.foo.bar.baz.1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32),
   121  					types.MakeMetricData("metric2.foo.bar.baz", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32),
   122  					types.MakeMetricData("metric3.foo.bar.baz.1", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
   123  					types.MakeMetricData("metric4.foo.bar.baz", []float64{4, math.NaN(), 5, 6, 7, 8}, 1, now32),
   124  				},
   125  			},
   126  			[]*types.MetricData{
   127  				types.MakeMetricData("foo.baz.1", []float64{2, math.NaN(), 2, 2, 2, 0}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "range"),
   128  				types.MakeMetricData("foo.baz", []float64{2, math.NaN(), 2, 0, 2, 3}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "range"),
   129  			},
   130  		},
   131  		{
   132  			`aggregateWithWildcards(metric[1234],"sum",1,3)`,
   133  			map[parser.MetricRequest][]*types.MetricData{
   134  				{Metric: "metric[1234]", From: 0, Until: 1}: {
   135  					types.MakeMetricData("metric1.foo1.bar.baz.qux", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32),
   136  					types.MakeMetricData("metric1.foo2.bar.baz.quux", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32),
   137  					types.MakeMetricData("metric1.foo3.bar.baz.qux", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
   138  					types.MakeMetricData("metric1.foo4.bar.baz.quux", []float64{4, math.NaN(), 5, 6, 7, 8}, 1, now32),
   139  				},
   140  			},
   141  			[]*types.MetricData{
   142  				types.MakeMetricData("metric1.bar.qux", []float64{4, math.NaN(), 6, 8, 10, 6}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "sum"),
   143  				types.MakeMetricData("metric1.bar.quux", []float64{6, math.NaN(), 8, 6, 12, 13}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "sum"),
   144  			},
   145  		},
   146  		{
   147  			`aggregateWithWildcards(metric[1234],"sum")`,
   148  			map[parser.MetricRequest][]*types.MetricData{
   149  				{Metric: "metric[1234]", From: 0, Until: 1}: {
   150  					types.MakeMetricData("metric1.foo1.bar.baz.qux", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32),
   151  					types.MakeMetricData("metric1.foo2.bar.baz.quux", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32),
   152  				},
   153  			},
   154  			[]*types.MetricData{
   155  				types.MakeMetricData("metric1.foo1.bar.baz.qux", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "sum"),
   156  				types.MakeMetricData("metric1.foo2.bar.baz.quux", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32).SetNameTag(`metric[1234]`).SetTag("aggregatedBy", "sum"),
   157  			},
   158  		},
   159  		{
   160  			`aggregateWithWildcards(metric[123456],"stddev",0,1,2)`,
   161  			map[parser.MetricRequest][]*types.MetricData{
   162  				{Metric: "metric[123456]", From: 0, Until: 1}: {
   163  					types.MakeMetricData("metric1.foo.bar.baz1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32),
   164  					types.MakeMetricData("metric2.foo.bar.baz2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32),
   165  					types.MakeMetricData("metric3.foo.bar.baz1", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32),
   166  					types.MakeMetricData("metric4.foo.bar.baz2", []float64{4, math.NaN(), 5, 6, 7, 8}, 1, now32),
   167  					types.MakeMetricData("metric5.foo.bar.baz1", []float64{5, math.NaN(), 6, 7, 8, 9}, 1, now32),
   168  					types.MakeMetricData("metric6.foo.bar.baz2", []float64{6, math.NaN(), 7, 8, 9, 10}, 1, now32),
   169  				},
   170  			},
   171  			[]*types.MetricData{
   172  				types.MakeMetricData("baz1", []float64{1.632993161855452, math.NaN(), 1.632993161855452, 1.632993161855452, 1.632993161855452, 1.5}, 1, now32).SetNameTag(`metric[123456]`).SetTag("aggregatedBy", "stddev"),
   173  				types.MakeMetricData("baz2", []float64{1.632993161855452, math.NaN(), 1.632993161855452, 1, 1.632993161855452, 2.0548046676563256}, 1, now32).SetNameTag(`metric[123456]`).SetTag("aggregatedBy", "stddev"),
   174  			},
   175  		},
   176  	}
   177  
   178  	for _, tt := range tests {
   179  		testName := tt.Target
   180  		t.Run(testName, func(t *testing.T) {
   181  			eval := th.EvaluatorFromFunc(md[0].F)
   182  			th.TestEvalExpr(t, eval, &tt)
   183  		})
   184  	}
   185  
   186  }
   187  
   188  func TestFunctionSumSeriesWithWildcards(t *testing.T) {
   189  	now32 := int64(time.Now().Unix())
   190  
   191  	tests := []th.MultiReturnEvalTestItem{
   192  		{
   193  			"sumSeriesWithWildcards(metric1.foo.*.*,1,2)",
   194  			map[parser.MetricRequest][]*types.MetricData{
   195  				{Metric: "metric1.foo.*.*", From: 0, Until: 1}: {
   196  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, now32),
   197  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, now32),
   198  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, now32),
   199  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, now32),
   200  				},
   201  			},
   202  			"sumSeriesWithWildcards",
   203  			map[string][]*types.MetricData{
   204  				"metric1.baz": {types.MakeMetricData("metric1.baz", []float64{12, 14, 16, 18, 20}, 1, now32).SetTag("aggregatedBy", "sum").SetNameTag("metric1.foo.*.*")},
   205  				"metric1.qux": {types.MakeMetricData("metric1.qux", []float64{13, 15, 17, 19, 21}, 1, now32).SetTag("aggregatedBy", "sum").SetNameTag("metric1.foo.*.*")},
   206  			},
   207  		},
   208  	}
   209  
   210  	for _, tt := range tests {
   211  		testName := tt.Target
   212  		t.Run(testName, func(t *testing.T) {
   213  			eval := th.EvaluatorFromFunc(md[0].F)
   214  			th.TestMultiReturnEvalExpr(t, eval, &tt)
   215  		})
   216  	}
   217  
   218  }
   219  
   220  // This return is multireturn
   221  func TestAverageSeriesWithWildcards(t *testing.T) {
   222  	now32 := int64(time.Now().Unix())
   223  
   224  	tests := []th.MultiReturnEvalTestItem{
   225  		{
   226  			"averageSeriesWithWildcards(metric1.foo.*.*,1,2)",
   227  			map[parser.MetricRequest][]*types.MetricData{
   228  				{Metric: "metric1.foo.*.*", From: 0, Until: 1}: {
   229  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, now32),
   230  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, now32),
   231  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, now32),
   232  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, now32),
   233  				},
   234  			},
   235  			"averageSeriesWithWildcards",
   236  			map[string][]*types.MetricData{
   237  				"metric1.baz": {types.MakeMetricData("metric1.baz", []float64{6, 7, 8, 9, 10}, 1, now32).SetTag("aggregatedBy", "average").SetNameTag("metric1.foo.*.*")},
   238  				"metric1.qux": {types.MakeMetricData("metric1.qux", []float64{6.5, 7.5, 8.5, 9.5, 10.5}, 1, now32).SetTag("aggregatedBy", "average").SetNameTag("metric1.foo.*.*")},
   239  			},
   240  		},
   241  	}
   242  
   243  	for _, tt := range tests {
   244  		testName := tt.Target
   245  		t.Run(testName, func(t *testing.T) {
   246  			eval := th.EvaluatorFromFunc(md[0].F)
   247  			th.TestMultiReturnEvalExpr(t, eval, &tt)
   248  		})
   249  	}
   250  
   251  }
   252  
   253  func TestFunctionMultiplySeriesWithWildcards(t *testing.T) {
   254  	now32 := int64(time.Now().Unix())
   255  
   256  	tests := []th.MultiReturnEvalTestItem{
   257  		{
   258  			"multiplySeriesWithWildcards(metric1.foo.*.*,1,2)",
   259  			map[parser.MetricRequest][]*types.MetricData{
   260  				{Metric: "metric1.foo.*.*", From: 0, Until: 1}: {
   261  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, now32),
   262  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 0, 8, 9, 10}, 1, now32),
   263  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, now32),
   264  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, now32),
   265  					types.MakeMetricData("metric1.foo.bar3.baz", []float64{2, 2, 2, 2, 2}, 1, now32),
   266  				},
   267  			},
   268  			"multiplySeriesWithWildcards",
   269  			map[string][]*types.MetricData{
   270  				"metric1.baz": {types.MakeMetricData("metric1.baz", []float64{22, 48, 78, 112, 150}, 1, now32).SetTag("aggregatedBy", "multiply").SetNameTag("metric1.foo.*.*")},
   271  				"metric1.qux": {types.MakeMetricData("metric1.qux", []float64{42, 0, 72, 90, 110}, 1, now32).SetTag("aggregatedBy", "multiply").SetNameTag("metric1.foo.*.*")},
   272  			},
   273  		},
   274  	}
   275  
   276  	for _, tt := range tests {
   277  		testName := tt.Target
   278  		t.Run(testName, func(t *testing.T) {
   279  			eval := th.EvaluatorFromFunc(md[0].F)
   280  			th.TestMultiReturnEvalExpr(t, eval, &tt)
   281  		})
   282  	}
   283  
   284  }
   285  
   286  func TestEmptyData(t *testing.T) {
   287  	tests := []th.EvalTestItem{
   288  		{
   289  			"multiplySeriesWithWildcards(metric1.foo.*.*,1,2)",
   290  			map[parser.MetricRequest][]*types.MetricData{
   291  				{Metric: "metric1.foo.*.*", From: 0, Until: 1}: {},
   292  			},
   293  			[]*types.MetricData{},
   294  		},
   295  	}
   296  
   297  	for _, tt := range tests {
   298  		testName := tt.Target
   299  		t.Run(testName, func(t *testing.T) {
   300  			eval := th.EvaluatorFromFunc(md[0].F)
   301  			th.TestEvalExpr(t, eval, &tt)
   302  		})
   303  	}
   304  }
   305  
   306  func BenchmarkMultiplySeriesWithWildcards(b *testing.B) {
   307  	benchmarks := []struct {
   308  		target string
   309  		M      map[parser.MetricRequest][]*types.MetricData
   310  	}{
   311  		{
   312  			target: "multiplySeriesWithWildcards(metric1.foo.bar*.*,1,2)",
   313  			M: map[parser.MetricRequest][]*types.MetricData{
   314  				{Metric: "metric1.foo.bar*.*", From: 0, Until: 1}: {
   315  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   316  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   317  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, 1),
   318  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, 1),
   319  				},
   320  			},
   321  		},
   322  		{
   323  			target: "multiplySeriesWithWildcards(metric1.foo.*.*,1,2)",
   324  			M: map[parser.MetricRequest][]*types.MetricData{
   325  				{Metric: "metric1.foo.*.*", From: 0, Until: 1}: {
   326  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   327  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   328  
   329  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, 1),
   330  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, 1),
   331  
   332  					types.MakeMetricData("metric1.foo.bar3.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   333  					types.MakeMetricData("metric1.foo.bar3.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   334  
   335  					types.MakeMetricData("metric1.foo.bar4.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   336  					types.MakeMetricData("metric1.foo.bar4.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   337  
   338  					types.MakeMetricData("metric1.foo.bar5.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   339  					types.MakeMetricData("metric1.foo.bar5.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   340  
   341  					types.MakeMetricData("metric1.foo.bar6.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   342  					types.MakeMetricData("metric1.foo.bar6.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   343  
   344  					types.MakeMetricData("metric1.foo.bar7.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   345  					types.MakeMetricData("metric1.foo.bar7.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   346  
   347  					types.MakeMetricData("metric1.foo.bar8.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   348  					types.MakeMetricData("metric1.foo.bar8.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   349  
   350  					types.MakeMetricData("metric1.foo.bar9.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   351  					types.MakeMetricData("metric1.foo.bar9.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   352  
   353  					types.MakeMetricData("metric1.foo.bar10.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   354  					types.MakeMetricData("metric1.foo.bar10.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   355  
   356  					types.MakeMetricData("metric1.foo.bar11.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   357  					types.MakeMetricData("metric1.foo.bar11.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   358  
   359  					types.MakeMetricData("metric1.foo.bar12.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   360  					types.MakeMetricData("metric1.foo.bar12.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   361  
   362  					types.MakeMetricData("metric1.foo.bar13.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   363  					types.MakeMetricData("metric1.foo.bar13.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   364  
   365  					types.MakeMetricData("metric1.foo.bar14.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   366  					types.MakeMetricData("metric1.foo.bar14.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   367  
   368  					types.MakeMetricData("metric1.foo.bar15.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   369  					types.MakeMetricData("metric1.foo.bar15.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   370  
   371  					types.MakeMetricData("metric1.foo.bar16.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   372  					types.MakeMetricData("metric1.foo.bar16.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   373  
   374  					types.MakeMetricData("metric1.foo.bar17.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   375  					types.MakeMetricData("metric1.foo.bar17.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   376  
   377  					types.MakeMetricData("metric1.foo.bar18.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   378  					types.MakeMetricData("metric1.foo.bar18.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   379  
   380  					types.MakeMetricData("metric1.foo.bar19.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   381  					types.MakeMetricData("metric1.foo.bar19.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   382  
   383  					types.MakeMetricData("metric1.foo.bar20.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   384  					types.MakeMetricData("metric1.foo.bar20.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   385  
   386  					types.MakeMetricData("metric1.foo.bar21.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   387  					types.MakeMetricData("metric1.foo.bar21.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   388  
   389  					types.MakeMetricData("metric1.foo.bar22.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   390  					types.MakeMetricData("metric1.foo.bar22.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   391  
   392  					types.MakeMetricData("metric1.foo.bar23.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   393  					types.MakeMetricData("metric1.foo.bar23.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   394  
   395  					types.MakeMetricData("metric1.foo.bar24.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   396  					types.MakeMetricData("metric1.foo.bar24.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   397  
   398  					types.MakeMetricData("metric1.foo.bar25.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   399  					types.MakeMetricData("metric1.foo.bar25.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   400  
   401  					types.MakeMetricData("metric1.foo.bar26.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   402  					types.MakeMetricData("metric1.foo.bar26.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   403  
   404  					types.MakeMetricData("metric1.foo.bar27.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   405  					types.MakeMetricData("metric1.foo.bar27.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   406  				},
   407  			},
   408  		},
   409  	}
   410  
   411  	eval := th.EvaluatorFromFunc(md[0].F)
   412  
   413  	for _, bm := range benchmarks {
   414  		b.Run(bm.target, func(b *testing.B) {
   415  			exp, _, err := parser.ParseExpr(bm.target)
   416  			if err != nil {
   417  				b.Fatalf("failed to parse %s: %+v", bm.target, err)
   418  			}
   419  
   420  			b.ResetTimer()
   421  
   422  			for i := 0; i < b.N; i++ {
   423  				g, err := eval.Eval(context.Background(), exp, 0, 1, bm.M)
   424  				if err != nil {
   425  					b.Fatalf("failed to eval %s: %+v", bm.target, err)
   426  				}
   427  				_ = g
   428  			}
   429  		})
   430  	}
   431  }
   432  
   433  func BenchmarkMultiplyAverageSeriesWithWildcards(b *testing.B) {
   434  	benchmarks := []struct {
   435  		target string
   436  		M      map[parser.MetricRequest][]*types.MetricData
   437  	}{
   438  		{
   439  			target: "averageSeriesWithWildcards(metric1.foo.bar*.*,1,2)",
   440  			M: map[parser.MetricRequest][]*types.MetricData{
   441  				{Metric: "metric1.foo.bar*.*", From: 0, Until: 1}: {
   442  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   443  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   444  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, 1),
   445  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, 1),
   446  				},
   447  			},
   448  		},
   449  		{
   450  			target: "averageSeriesWithWildcards(metric1.foo.*.*,1,2)",
   451  			M: map[parser.MetricRequest][]*types.MetricData{
   452  				{Metric: "metric1.foo.*.*", From: 0, Until: 1}: {
   453  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   454  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   455  
   456  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, 1),
   457  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, 1),
   458  
   459  					types.MakeMetricData("metric1.foo.bar3.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   460  					types.MakeMetricData("metric1.foo.bar3.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   461  
   462  					types.MakeMetricData("metric1.foo.bar4.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   463  					types.MakeMetricData("metric1.foo.bar4.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   464  
   465  					types.MakeMetricData("metric1.foo.bar5.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   466  					types.MakeMetricData("metric1.foo.bar5.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   467  
   468  					types.MakeMetricData("metric1.foo.bar6.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   469  					types.MakeMetricData("metric1.foo.bar6.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   470  
   471  					types.MakeMetricData("metric1.foo.bar7.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   472  					types.MakeMetricData("metric1.foo.bar7.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   473  
   474  					types.MakeMetricData("metric1.foo.bar8.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   475  					types.MakeMetricData("metric1.foo.bar8.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   476  
   477  					types.MakeMetricData("metric1.foo.bar9.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   478  					types.MakeMetricData("metric1.foo.bar9.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   479  
   480  					types.MakeMetricData("metric1.foo.bar10.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   481  					types.MakeMetricData("metric1.foo.bar10.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   482  
   483  					types.MakeMetricData("metric1.foo.bar11.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   484  					types.MakeMetricData("metric1.foo.bar11.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   485  
   486  					types.MakeMetricData("metric1.foo.bar12.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   487  					types.MakeMetricData("metric1.foo.bar12.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   488  
   489  					types.MakeMetricData("metric1.foo.bar13.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   490  					types.MakeMetricData("metric1.foo.bar13.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   491  
   492  					types.MakeMetricData("metric1.foo.bar14.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   493  					types.MakeMetricData("metric1.foo.bar14.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   494  
   495  					types.MakeMetricData("metric1.foo.bar15.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   496  					types.MakeMetricData("metric1.foo.bar15.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   497  
   498  					types.MakeMetricData("metric1.foo.bar16.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   499  					types.MakeMetricData("metric1.foo.bar16.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   500  
   501  					types.MakeMetricData("metric1.foo.bar17.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   502  					types.MakeMetricData("metric1.foo.bar17.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   503  
   504  					types.MakeMetricData("metric1.foo.bar18.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   505  					types.MakeMetricData("metric1.foo.bar18.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   506  
   507  					types.MakeMetricData("metric1.foo.bar19.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   508  					types.MakeMetricData("metric1.foo.bar19.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   509  
   510  					types.MakeMetricData("metric1.foo.bar20.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   511  					types.MakeMetricData("metric1.foo.bar20.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   512  
   513  					types.MakeMetricData("metric1.foo.bar21.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   514  					types.MakeMetricData("metric1.foo.bar21.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   515  
   516  					types.MakeMetricData("metric1.foo.bar22.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   517  					types.MakeMetricData("metric1.foo.bar22.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   518  
   519  					types.MakeMetricData("metric1.foo.bar23.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   520  					types.MakeMetricData("metric1.foo.bar23.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   521  
   522  					types.MakeMetricData("metric1.foo.bar24.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   523  					types.MakeMetricData("metric1.foo.bar24.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   524  
   525  					types.MakeMetricData("metric1.foo.bar25.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   526  					types.MakeMetricData("metric1.foo.bar25.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   527  
   528  					types.MakeMetricData("metric1.foo.bar26.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   529  					types.MakeMetricData("metric1.foo.bar26.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   530  
   531  					types.MakeMetricData("metric1.foo.bar27.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   532  					types.MakeMetricData("metric1.foo.bar27.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   533  				},
   534  			},
   535  		},
   536  	}
   537  
   538  	eval := th.EvaluatorFromFunc(md[0].F)
   539  
   540  	for _, bm := range benchmarks {
   541  		b.Run(bm.target, func(b *testing.B) {
   542  			exp, _, err := parser.ParseExpr(bm.target)
   543  			if err != nil {
   544  				b.Fatalf("failed to parse %s: %+v", bm.target, err)
   545  			}
   546  
   547  			b.ResetTimer()
   548  
   549  			for i := 0; i < b.N; i++ {
   550  				g, err := eval.Eval(context.Background(), exp, 0, 1, bm.M)
   551  				if err != nil {
   552  					b.Fatalf("failed to eval %s: %+v", bm.target, err)
   553  				}
   554  				_ = g
   555  			}
   556  		})
   557  	}
   558  }
   559  
   560  func BenchmarkSumSeriesWithWildcards(b *testing.B) {
   561  	benchmarks := []struct {
   562  		target string
   563  		M      map[parser.MetricRequest][]*types.MetricData
   564  	}{
   565  		{
   566  			target: "sumSeriesWithWildcards(metric1.foo.bar*.*,1,2)",
   567  			M: map[parser.MetricRequest][]*types.MetricData{
   568  				{Metric: "metric1.foo.bar*.*", From: 0, Until: 1}: {
   569  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   570  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   571  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, 1),
   572  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, 1),
   573  				},
   574  			},
   575  		},
   576  		{
   577  			target: "sumSeriesWithWildcards(metric1.foo.*.*,1,2)",
   578  			M: map[parser.MetricRequest][]*types.MetricData{
   579  				{Metric: "metric1.foo.*.*", From: 0, Until: 1}: {
   580  					types.MakeMetricData("metric1.foo.bar1.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   581  					types.MakeMetricData("metric1.foo.bar1.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   582  
   583  					types.MakeMetricData("metric1.foo.bar2.baz", []float64{11, 12, 13, 14, 15}, 1, 1),
   584  					types.MakeMetricData("metric1.foo.bar2.qux", []float64{7, 8, 9, 10, 11}, 1, 1),
   585  
   586  					types.MakeMetricData("metric1.foo.bar3.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   587  					types.MakeMetricData("metric1.foo.bar3.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   588  
   589  					types.MakeMetricData("metric1.foo.bar4.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   590  					types.MakeMetricData("metric1.foo.bar4.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   591  
   592  					types.MakeMetricData("metric1.foo.bar5.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   593  					types.MakeMetricData("metric1.foo.bar5.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   594  
   595  					types.MakeMetricData("metric1.foo.bar6.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   596  					types.MakeMetricData("metric1.foo.bar6.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   597  
   598  					types.MakeMetricData("metric1.foo.bar7.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   599  					types.MakeMetricData("metric1.foo.bar7.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   600  
   601  					types.MakeMetricData("metric1.foo.bar8.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   602  					types.MakeMetricData("metric1.foo.bar8.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   603  
   604  					types.MakeMetricData("metric1.foo.bar9.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   605  					types.MakeMetricData("metric1.foo.bar9.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   606  
   607  					types.MakeMetricData("metric1.foo.bar10.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   608  					types.MakeMetricData("metric1.foo.bar10.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   609  
   610  					types.MakeMetricData("metric1.foo.bar11.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   611  					types.MakeMetricData("metric1.foo.bar11.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   612  
   613  					types.MakeMetricData("metric1.foo.bar12.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   614  					types.MakeMetricData("metric1.foo.bar12.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   615  
   616  					types.MakeMetricData("metric1.foo.bar13.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   617  					types.MakeMetricData("metric1.foo.bar13.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   618  
   619  					types.MakeMetricData("metric1.foo.bar14.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   620  					types.MakeMetricData("metric1.foo.bar14.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   621  
   622  					types.MakeMetricData("metric1.foo.bar15.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   623  					types.MakeMetricData("metric1.foo.bar15.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   624  
   625  					types.MakeMetricData("metric1.foo.bar16.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   626  					types.MakeMetricData("metric1.foo.bar16.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   627  
   628  					types.MakeMetricData("metric1.foo.bar17.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   629  					types.MakeMetricData("metric1.foo.bar17.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   630  
   631  					types.MakeMetricData("metric1.foo.bar18.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   632  					types.MakeMetricData("metric1.foo.bar18.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   633  
   634  					types.MakeMetricData("metric1.foo.bar19.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   635  					types.MakeMetricData("metric1.foo.bar19.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   636  
   637  					types.MakeMetricData("metric1.foo.bar20.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   638  					types.MakeMetricData("metric1.foo.bar20.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   639  
   640  					types.MakeMetricData("metric1.foo.bar21.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   641  					types.MakeMetricData("metric1.foo.bar21.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   642  
   643  					types.MakeMetricData("metric1.foo.bar22.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   644  					types.MakeMetricData("metric1.foo.bar22.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   645  
   646  					types.MakeMetricData("metric1.foo.bar23.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   647  					types.MakeMetricData("metric1.foo.bar23.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   648  
   649  					types.MakeMetricData("metric1.foo.bar24.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   650  					types.MakeMetricData("metric1.foo.bar24.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   651  
   652  					types.MakeMetricData("metric1.foo.bar25.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   653  					types.MakeMetricData("metric1.foo.bar25.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   654  
   655  					types.MakeMetricData("metric1.foo.bar26.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   656  					types.MakeMetricData("metric1.foo.bar26.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   657  
   658  					types.MakeMetricData("metric1.foo.bar27.baz", []float64{1, 2, 3, 4, 5}, 1, 1),
   659  					types.MakeMetricData("metric1.foo.bar27.qux", []float64{6, 7, 8, 9, 10}, 1, 1),
   660  				},
   661  			},
   662  		},
   663  	}
   664  
   665  	for _, bm := range benchmarks {
   666  		b.Run(bm.target, func(b *testing.B) {
   667  			exp, _, err := parser.ParseExpr(bm.target)
   668  			if err != nil {
   669  				b.Fatalf("failed to parse %s: %+v", bm.target, err)
   670  			}
   671  
   672  			eval := th.EvaluatorFromFunc(md[0].F)
   673  
   674  			b.ResetTimer()
   675  
   676  			for i := 0; i < b.N; i++ {
   677  				g, err := eval.Eval(context.Background(), exp, 0, 1, bm.M)
   678  				if err != nil {
   679  					b.Fatalf("failed to eval %s: %+v", bm.target, err)
   680  				}
   681  				_ = g
   682  			}
   683  		})
   684  	}
   685  }