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

     1  package weightedAverage
     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 None = math.NaN()
    17  
    18  var (
    19  	md []interfaces.FunctionMetadata = New("")
    20  )
    21  
    22  func init() {
    23  	for _, m := range md {
    24  		metadata.RegisterFunction(m.Name, m.F)
    25  	}
    26  }
    27  
    28  func TestWeightedAverage(t *testing.T) {
    29  	now32 := int64(time.Now().Unix())
    30  
    31  	tests := []th.EvalTestItem{
    32  		{
    33  			"weightedAverage(metric*, metric*, 0)",
    34  			map[parser.MetricRequest][]*types.MetricData{
    35  				{Metric: "metric*", From: 0, Until: 1}: {},
    36  			},
    37  			[]*types.MetricData{},
    38  		},
    39  		{
    40  			"weightedAverage(metric*, metric*, 0)",
    41  			map[parser.MetricRequest][]*types.MetricData{
    42  				{Metric: "metric*", From: 0, Until: 1}: {
    43  					types.MakeMetricData("metric1", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
    44  					types.MakeMetricData("metric2", []float64{None, 2, None, 4, None, 6, None, 8, None, 10, None, 12, None, 14, None, 16, None, 18, None, 20}, 1, now32),
    45  					types.MakeMetricData("metric3", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, None, None, None}, 1, now32),
    46  					types.MakeMetricData("metric4", []float64{1, 2, 3, 4, None, 6, None, None, 9, 10, 11, None, 13, None, None, None, None, 18, 19, 20}, 1, now32),
    47  					types.MakeMetricData("metric5", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, None, None}, 1, now32),
    48  				},
    49  			},
    50  			[]*types.MetricData{types.MakeMetricData(
    51  				"weightedAverage(metric*, metric*, 0)", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
    52  			},
    53  		},
    54  		{
    55  			"weightedAverage(metric*.dividend, metric*.divisor, 0)",
    56  			map[parser.MetricRequest][]*types.MetricData{
    57  				{Metric: "metric*.dividend", From: 0, Until: 1}: {
    58  					types.MakeMetricData("metric1.dividend", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
    59  					types.MakeMetricData("metric2.dividend", []float64{None, 2, None, 4, None, 6, None, 8, None, 10, None, 12, None, 14, None, 16, None, 18, None, 20}, 1, now32),
    60  					types.MakeMetricData("metric3.dividend", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, None, None, None}, 1, now32),
    61  					types.MakeMetricData("metric5.dividend", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, None, None}, 1, now32),
    62  				},
    63  				{Metric: "metric*.divisor", From: 0, Until: 1}: {
    64  					types.MakeMetricData("metric1.divisor", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
    65  					types.MakeMetricData("metric3.divisor", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, None, None, None}, 1, now32),
    66  					types.MakeMetricData("metric4.divisor", []float64{1, 2, 3, 4, None, 6, None, None, 9, 10, 11, None, 13, None, None, None, None, 18, 19, 20}, 1, now32),
    67  					types.MakeMetricData("metric5.divisor", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, None, None}, 1, now32),
    68  				},
    69  			},
    70  			[]*types.MetricData{types.MakeMetricData(
    71  				"weightedAverage(metric*.dividend, metric*.divisor, 0)",
    72  				[]float64{0.75, 1.5, 1.5, 2.0, 5.0, 4.5, 7.0, 8.0, 6.75, 7.5, 8.25, 12.0, 9.75, 14.0, 15.0, 16.0, 17.0, 12.0, 9.5, 10.0}, 1, now32,
    73  			),
    74  			},
    75  		},
    76  		{
    77  			"weightedAverage(metric1.dividend, metric2.divisor, 0)",
    78  			map[parser.MetricRequest][]*types.MetricData{
    79  				{Metric: "metric1.dividend", From: 0, Until: 1}: {
    80  					types.MakeMetricData("metric1.dividend", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
    81  				},
    82  				{Metric: "metric2.divisor", From: 0, Until: 1}: {
    83  					types.MakeMetricData("metric2.divisor", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
    84  				},
    85  			},
    86  			[]*types.MetricData{},
    87  		},
    88  	}
    89  
    90  	for _, tt := range tests {
    91  		testName := tt.Target
    92  		t.Run(testName, func(t *testing.T) {
    93  			eval := th.EvaluatorFromFunc(md[0].F)
    94  			th.TestEvalExpr(t, eval, &tt)
    95  		})
    96  	}
    97  
    98  }
    99  
   100  func BenchmarkWeightedAverage(b *testing.B) {
   101  	now32 := time.Now().Unix()
   102  
   103  	benchmarks := []struct {
   104  		target string
   105  		M      map[parser.MetricRequest][]*types.MetricData
   106  	}{
   107  		{
   108  			target: "weightedAverage(metric*, metric*, 0)",
   109  			M: map[parser.MetricRequest][]*types.MetricData{
   110  				{Metric: "metric*", From: 0, Until: 1}: {
   111  					types.MakeMetricData("metric1", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
   112  					types.MakeMetricData("metric2", []float64{None, 2, None, 4, None, 6, None, 8, None, 10, None, 12, None, 14, None, 16, None, 18, None, 20}, 1, now32),
   113  					types.MakeMetricData("metric3", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, None, None, None}, 1, now32),
   114  					types.MakeMetricData("metric4", []float64{1, 2, 3, 4, None, 6, None, None, 9, 10, 11, None, 13, None, None, None, None, 18, 19, 20}, 1, now32),
   115  					types.MakeMetricData("metric5", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, None, None}, 1, now32),
   116  				},
   117  			},
   118  		},
   119  		{
   120  			target: "weightedAverage(metric*.dividend, metric*.divisor, 0)",
   121  			M: map[parser.MetricRequest][]*types.MetricData{
   122  				{Metric: "metric*.dividend", From: 0, Until: 1}: {
   123  					types.MakeMetricData("metric1.dividend", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
   124  					types.MakeMetricData("metric2.dividend", []float64{None, 2, None, 4, None, 6, None, 8, None, 10, None, 12, None, 14, None, 16, None, 18, None, 20}, 1, now32),
   125  					types.MakeMetricData("metric3.dividend", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, None, None, None}, 1, now32),
   126  					types.MakeMetricData("metric5.dividend", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, None, None}, 1, now32),
   127  				},
   128  				{Metric: "metric*.divisor", From: 0, Until: 1}: {
   129  					types.MakeMetricData("metric1.divisor", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
   130  					types.MakeMetricData("metric3.divisor", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, None, None, None}, 1, now32),
   131  					types.MakeMetricData("metric4.divisor", []float64{1, 2, 3, 4, None, 6, None, None, 9, 10, 11, None, 13, None, None, None, None, 18, 19, 20}, 1, now32),
   132  					types.MakeMetricData("metric5.divisor", []float64{1, 2, None, None, None, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, None, None}, 1, now32),
   133  				},
   134  			},
   135  		},
   136  		{
   137  			// empty result
   138  			target: "weightedAverage(metric1.dividend, metric2.divisor, 0)",
   139  			M: map[parser.MetricRequest][]*types.MetricData{
   140  				{Metric: "metric1.dividend", From: 0, Until: 1}: {
   141  					types.MakeMetricData("metric1.dividend", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
   142  				},
   143  				{Metric: "metric2.divisor", From: 0, Until: 1}: {
   144  					types.MakeMetricData("metric2.divisor", []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 1, now32),
   145  				},
   146  			},
   147  		},
   148  	}
   149  
   150  	eval := th.EvaluatorFromFunc(md[0].F)
   151  
   152  	for _, bm := range benchmarks {
   153  		b.Run(bm.target, func(b *testing.B) {
   154  			exp, _, err := parser.ParseExpr(bm.target)
   155  			if err != nil {
   156  				b.Fatalf("failed to parse %s: %+v", bm.target, err)
   157  			}
   158  
   159  			b.ResetTimer()
   160  
   161  			for i := 0; i < b.N; i++ {
   162  				g, err := eval.Eval(context.Background(), exp, 0, 1, bm.M)
   163  				if err != nil {
   164  					b.Fatalf("failed to eval %s: %+v", bm.target, err)
   165  				}
   166  				_ = g
   167  			}
   168  		})
   169  	}
   170  }