func (ev *evaluator) eval(expr Expr) Value {
	if err := contextDone(ev.ctx, "expression evaluation"); err != nil {
		ev.error(err)
	}
	numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1
	switch e := expr.(type) {
	case *AggregateExpr:
		if s, ok := e.Param.(*StringLiteral); ok {
			return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
				return ev.aggregation(e.Op, e.Grouping, e.Without, s.Val, v[0].(Vector), enh)
			}, e.Expr)
		}
		return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
			var param float64
			if e.Param != nil {
				param = v[0].(Vector)[0].V
			}
			return ev.aggregation(e.Op, e.Grouping, e.Without, param, v[1].(Vector), enh)
		}, e.Param, e.Expr)
	case *Call:
		if e.Func.Name == "timestamp" {
			vs, ok := e.Args[0].(*VectorSelector)
			if ok {
				return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
					return e.Func.Call([]Value{ev.vectorSelector(vs, enh.ts)}, e.Args, enh)
				})
			}
		}
		var matrixArgIndex int
		var matrixArg bool
		for i, a := range e.Args {
			_, ok := a.(*MatrixSelector)
			if ok {
				matrixArgIndex = i
				matrixArg = true
				break
			}
		}
		if !matrixArg {
			return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
				return e.Func.Call(v, e.Args, enh)
			}, e.Args...)
		}
		inArgs := make([]Value, len(e.Args))
		otherArgs := make([]Matrix, len(e.Args))
		otherInArgs := make([]Vector, len(e.Args))
		for i, e := range e.Args {
			if i != matrixArgIndex {
				otherArgs[i] = ev.eval(e).(Matrix)
				otherInArgs[i] = Vector{Sample{}}
				inArgs[i] = otherInArgs[i]
			}
		}
		sel := e.Args[matrixArgIndex].(*MatrixSelector)
		mat := make(Matrix, 0, len(sel.series))  
		offset := durationMilliseconds(sel.Offset)
		selRange := durationMilliseconds(sel.Range)
		points := getPointSlice(16)
		inMatrix := make(Matrix, 1)
		inArgs[matrixArgIndex] = inMatrix
		enh := &EvalNodeHelper{out: make(Vector, 0, 1)}
		var it *storage.BufferedSeriesIterator
		for i, s := range sel.series {
			if it == nil {
				it = storage.NewBuffer(s.Iterator(), selRange)
			} else {
				it.Reset(s.Iterator())
			}
			ss := Series{
				Metric: dropMetricName(sel.series[i].Labels()),
				Points: getPointSlice(numSteps),
			}
			inMatrix[0].Metric = sel.series[i].Labels()
			for ts, step := ev.startTimestamp, -1; ts <= ev.endTimestamp; ts += ev.interval {
				step++
				for j := range e.Args {
					if j != matrixArgIndex {
						otherInArgs[j][0].V = otherArgs[j][0].Points[step].V
					}
				}
				maxt := ts - offset
				mint := maxt - selRange
				points = ev.matrixIterSlice(it, mint, maxt, points[:0])
				if len(points) == 0 {
					continue
				}
				inMatrix[0].Points = points
				enh.ts = ts
				outVec := e.Func.Call(inArgs, e.Args, enh)
				enh.out = outVec[:0]
				if len(outVec) > 0 {
					ss.Points = append(ss.Points, Point{V: outVec[0].Point.V, T: ts})
				}
			}
			if len(ss.Points) > 0 {
				mat = append(mat, ss)
			}
		}
		putPointSlice(points)
		return mat
	case *ParenExpr:
		return ev.eval(e.Expr)
	case *UnaryExpr:
		mat := ev.eval(e.Expr).(Matrix)
		if e.Op == itemSUB {
			for i := range mat {
				mat[i].Metric = dropMetricName(mat[i].Metric)
				for j := range mat[i].Points {
					mat[i].Points[j].V = -mat[i].Points[j].V
				}
			}
		}
		return mat
	case *BinaryExpr:
		switch lt, rt := e.LHS.Type(), e.RHS.Type(); {
		case lt == ValueTypeScalar && rt == ValueTypeScalar:
			return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
				val := scalarBinop(e.Op, v[0].(Vector)[0].Point.V, v[1].(Vector)[0].Point.V)
				return append(enh.out, Sample{Point: Point{V: val}})
			}, e.LHS, e.RHS)
		case lt == ValueTypeVector && rt == ValueTypeVector:
			switch e.Op {
			case itemLAND:
				return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
					return ev.VectorAnd(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
				}, e.LHS, e.RHS)
			case itemLOR:
				return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
					return ev.VectorOr(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
				}, e.LHS, e.RHS)
			case itemLUnless:
				return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
					return ev.VectorUnless(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
				}, e.LHS, e.RHS)
			default:
				return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
					return ev.VectorBinop(e.Op, v[0].(Vector), v[1].(Vector), e.VectorMatching, e.ReturnBool, enh)
				}, e.LHS, e.RHS)
			}
		case lt == ValueTypeVector && rt == ValueTypeScalar:
			return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
				return ev.VectorscalarBinop(e.Op, v[0].(Vector), Scalar{V: v[1].(Vector)[0].Point.V}, false, e.ReturnBool, enh)
			}, e.LHS, e.RHS)
		case lt == ValueTypeScalar && rt == ValueTypeVector:
			return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
				return ev.VectorscalarBinop(e.Op, v[1].(Vector), Scalar{V: v[0].(Vector)[0].Point.V}, true, e.ReturnBool, enh)
			}, e.LHS, e.RHS)
		}
	case *NumberLiteral:
		return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
			return append(enh.out, Sample{Point: Point{V: e.Val}})
		})
	case *VectorSelector:
		mat := make(Matrix, 0, len(e.series))
		var it *storage.BufferedSeriesIterator
		for i, s := range e.series {
			if it == nil {
				it = storage.NewBuffer(s.Iterator(), durationMilliseconds(LookbackDelta))
			} else {
				it.Reset(s.Iterator())
			}
			ss := Series{
				Metric: e.series[i].Labels(),
				Points: getPointSlice(numSteps),
			}
			for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval {
				_, v, ok := ev.vectorSelectorSingle(it, e, ts)
				if ok {
					ss.Points = append(ss.Points, Point{V: v, T: ts})
				}
			}
			if len(ss.Points) > 0 {
				mat = append(mat, ss)
			}
		}
		return mat
	case *MatrixSelector:
		if ev.startTimestamp != ev.endTimestamp {
			panic(fmt.Errorf("cannot do range evaluation of matrix selector"))
		}
		return ev.matrixSelector(e)
	}
	panic(fmt.Errorf("unhandled expression of type: %T", expr))
}
eval evaluates the given expression as the given AST expression node requires.
package promql
import (
	"container/heap"
	"context"
	"fmt"
	"math"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"sync"
	"time"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/prometheus/pkg/labels"
	"github.com/prometheus/prometheus/pkg/timestamp"
	"github.com/prometheus/prometheus/pkg/value"
	"github.com/prometheus/prometheus/storage"
	"github.com/prometheus/prometheus/util/stats"
)
const (
	namespace = "prometheus"
	subsystem = "engine"
	queryTag  = "query"
	maxInt64 = 9223372036854774784
	minInt64 = -9223372036854775808
)
type engineMetrics struct {
	currentQueries       prometheus.Gauge
	maxConcurrentQueries prometheus.Gauge
	queryQueueTime       prometheus.Summary
	queryPrepareTime     prometheus.Summary
	queryInnerEval       prometheus.Summary
	queryResultSort      prometheus.Summary
}
func convertibleToInt64(v float64) bool {
	return v <= maxInt64 && v >= minInt64
}
type (
	ErrQueryTimeout string
	ErrQueryCanceled string
	ErrStorage error
)
func (e ErrQueryTimeout) Error() string  { return fmt.Sprintf("query timed out in %s", string(e)) }
func (e ErrQueryCanceled) Error() string { return fmt.Sprintf("query was canceled in %s", string(e)) }
type Query interface {
	Exec(ctx context.Context) *Result
	Close()
	Statement() Statement
	Stats() *stats.TimerGroup
	Cancel()
}
type query struct {
	queryable storage.Queryable
	q string
	stmt Statement
	stats *stats.TimerGroup
	matrix Matrix
	cancel func()
	ng *Engine
}
func (q *query) Statement() Statement {
	return q.stmt
}
func (q *query) Stats() *stats.TimerGroup {
	return q.stats
}
func (q *query) Cancel() {
	if q.cancel != nil {
		q.cancel()
	}
}
func (q *query) Close() {
	for _, s := range q.matrix {
		putPointSlice(s.Points)
	}
}
func (q *query) Exec(ctx context.Context) *Result {
	if span := opentracing.SpanFromContext(ctx); span != nil {
		span.SetTag(queryTag, q.stmt.String())
	}
	res, err := q.ng.exec(ctx, q)
	return &Result{Err: err, Value: res}
}
func contextDone(ctx context.Context, env string) error {
	select {
	case <-ctx.Done():
		err := ctx.Err()
		switch err {
		case context.Canceled:
			return ErrQueryCanceled(env)
		case context.DeadlineExceeded:
			return ErrQueryTimeout(env)
		default:
			return err
		}
	default:
		return nil
	}
}
type Engine struct {
	logger  log.Logger
	metrics *engineMetrics
	timeout time.Duration
	gate    *queryGate
}
func NewEngine(logger log.Logger, reg prometheus.Registerer, maxConcurrent int, timeout time.Duration) *Engine {
	if logger == nil {
		logger = log.NewNopLogger()
	}
	metrics := &engineMetrics{
		currentQueries: prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace: namespace,
			Subsystem: subsystem,
			Name:      "queries",
			Help:      "The current number of queries being executed or waiting.",
		}),
		maxConcurrentQueries: prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace: namespace,
			Subsystem: subsystem,
			Name:      "queries_concurrent_max",
			Help:      "The max number of concurrent queries.",
		}),
		queryQueueTime: prometheus.NewSummary(prometheus.SummaryOpts{
			Namespace:   namespace,
			Subsystem:   subsystem,
			Name:        "query_duration_seconds",
			Help:        "Query timings",
			ConstLabels: prometheus.Labels{"slice": "queue_time"},
		}),
		queryPrepareTime: prometheus.NewSummary(prometheus.SummaryOpts{
			Namespace:   namespace,
			Subsystem:   subsystem,
			Name:        "query_duration_seconds",
			Help:        "Query timings",
			ConstLabels: prometheus.Labels{"slice": "prepare_time"},
		}),
		queryInnerEval: prometheus.NewSummary(prometheus.SummaryOpts{
			Namespace:   namespace,
			Subsystem:   subsystem,
			Name:        "query_duration_seconds",
			Help:        "Query timings",
			ConstLabels: prometheus.Labels{"slice": "inner_eval"},
		}),
		queryResultSort: prometheus.NewSummary(prometheus.SummaryOpts{
			Namespace:   namespace,
			Subsystem:   subsystem,
			Name:        "query_duration_seconds",
			Help:        "Query timings",
			ConstLabels: prometheus.Labels{"slice": "result_sort"},
		}),
	}
	metrics.maxConcurrentQueries.Set(float64(maxConcurrent))
	if reg != nil {
		reg.MustRegister(
			metrics.currentQueries,
			metrics.maxConcurrentQueries,
			metrics.queryInnerEval,
			metrics.queryPrepareTime,
			metrics.queryResultSort,
		)
	}
	return &Engine{
		gate:    newQueryGate(maxConcurrent),
		timeout: timeout,
		logger:  logger,
		metrics: metrics,
	}
}
func (ng *Engine) NewInstantQuery(q storage.Queryable, qs string, ts time.Time) (Query, error) {
	expr, err := ParseExpr(qs)
	if err != nil {
		return nil, err
	}
	qry := ng.newQuery(q, expr, ts, ts, 0)
	qry.q = qs
	return qry, nil
}
func (ng *Engine) NewRangeQuery(q storage.Queryable, qs string, start, end time.Time, interval time.Duration) (Query, error) {
	expr, err := ParseExpr(qs)
	if err != nil {
		return nil, err
	}
	if expr.Type() != ValueTypeVector && expr.Type() != ValueTypeScalar {
		return nil, fmt.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", documentedType(expr.Type()))
	}
	qry := ng.newQuery(q, expr, start, end, interval)
	qry.q = qs
	return qry, nil
}
func (ng *Engine) newQuery(q storage.Queryable, expr Expr, start, end time.Time, interval time.Duration) *query {
	es := &EvalStmt{
		Expr:     expr,
		Start:    start,
		End:      end,
		Interval: interval,
	}
	qry := &query{
		stmt:      es,
		ng:        ng,
		stats:     stats.NewTimerGroup(),
		queryable: q,
	}
	return qry
}
type testStmt func(context.Context) error
func (testStmt) String() string { return "test statement" }
func (testStmt) stmt()          {}
func (ng *Engine) newTestQuery(f func(context.Context) error) Query {
	qry := &query{
		q:     "test statement",
		stmt:  testStmt(f),
		ng:    ng,
		stats: stats.NewTimerGroup(),
	}
	return qry
}
func (ng *Engine) exec(ctx context.Context, q *query) (Value, error) {
	ng.metrics.currentQueries.Inc()
	defer ng.metrics.currentQueries.Dec()
	ctx, cancel := context.WithTimeout(ctx, ng.timeout)
	q.cancel = cancel
	execTimer := q.stats.GetTimer(stats.ExecTotalTime).Start()
	defer execTimer.Stop()
	queueTimer := q.stats.GetTimer(stats.ExecQueueTime).Start()
	if err := ng.gate.Start(ctx); err != nil {
		return nil, err
	}
	defer ng.gate.Done()
	queueTimer.Stop()
	ng.metrics.queryQueueTime.Observe(queueTimer.ElapsedTime().Seconds())
	defer q.cancel()
	const env = "query execution"
	evalTimer := q.stats.GetTimer(stats.EvalTotalTime).Start()
	defer evalTimer.Stop()
	if err := contextDone(ctx, env); err != nil {
		return nil, err
	}
	switch s := q.Statement().(type) {
	case *EvalStmt:
		return ng.execEvalStmt(ctx, q, s)
	case testStmt:
		return nil, s(ctx)
	}
	panic(fmt.Errorf("promql.Engine.exec: unhandled statement of type %T", q.Statement()))
}
func timeMilliseconds(t time.Time) int64 {
	return t.UnixNano() / int64(time.Millisecond/time.Nanosecond)
}
func durationMilliseconds(d time.Duration) int64 {
	return int64(d / (time.Millisecond / time.Nanosecond))
}
func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (Value, error) {
	prepareTimer := query.stats.GetTimer(stats.QueryPreparationTime).Start()
	querier, err := ng.populateSeries(ctx, query.queryable, s)
	prepareTimer.Stop()
	ng.metrics.queryPrepareTime.Observe(prepareTimer.ElapsedTime().Seconds())
	if querier != nil {
		defer querier.Close()
	}
	if err != nil {
		return nil, err
	}
	evalTimer := query.stats.GetTimer(stats.InnerEvalTime).Start()
	if s.Start == s.End && s.Interval == 0 {
		start := timeMilliseconds(s.Start)
		evaluator := &evaluator{
			startTimestamp: start,
			endTimestamp:   start,
			interval:       1,
			ctx:            ctx,
			logger:         ng.logger,
		}
		val, err := evaluator.Eval(s.Expr)
		if err != nil {
			return nil, err
		}
		evalTimer.Stop()
		ng.metrics.queryInnerEval.Observe(evalTimer.ElapsedTime().Seconds())
		mat, ok := val.(Matrix)
		if !ok {
			panic(fmt.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
		}
		query.matrix = mat
		switch s.Expr.Type() {
		case ValueTypeVector:
			vector := make(Vector, len(mat))
			for i, s := range mat {
				vector[i] = Sample{Metric: s.Metric, Point: Point{V: s.Points[0].V, T: start}}
			}
			return vector, nil
		case ValueTypeScalar:
			return Scalar{V: mat[0].Points[0].V, T: start}, nil
		case ValueTypeMatrix:
			return mat, nil
		default:
			panic(fmt.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type()))
		}
	}
	evaluator := &evaluator{
		startTimestamp: timeMilliseconds(s.Start),
		endTimestamp:   timeMilliseconds(s.End),
		interval:       durationMilliseconds(s.Interval),
		ctx:            ctx,
		logger:         ng.logger,
	}
	val, err := evaluator.Eval(s.Expr)
	if err != nil {
		return nil, err
	}
	evalTimer.Stop()
	ng.metrics.queryInnerEval.Observe(evalTimer.ElapsedTime().Seconds())
	mat, ok := val.(Matrix)
	if !ok {
		panic(fmt.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
	}
	query.matrix = mat
	if err := contextDone(ctx, "expression evaluation"); err != nil {
		return nil, err
	}
	sortTimer := query.stats.GetTimer(stats.ResultSortTime).Start()
	sort.Sort(mat)
	sortTimer.Stop()
	ng.metrics.queryResultSort.Observe(sortTimer.ElapsedTime().Seconds())
	return mat, nil
}
func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *EvalStmt) (storage.Querier, error) {
	var maxOffset time.Duration
	Inspect(s.Expr, func(node Node, _ []Node) bool {
		switch n := node.(type) {
		case *VectorSelector:
			if maxOffset < LookbackDelta {
				maxOffset = LookbackDelta
			}
			if n.Offset+LookbackDelta > maxOffset {
				maxOffset = n.Offset + LookbackDelta
			}
		case *MatrixSelector:
			if maxOffset < n.Range {
				maxOffset = n.Range
			}
			if n.Offset+n.Range > maxOffset {
				maxOffset = n.Offset + n.Range
			}
		}
		return true
	})
	mint := s.Start.Add(-maxOffset)
	querier, err := q.Querier(ctx, timestamp.FromTime(mint), timestamp.FromTime(s.End))
	if err != nil {
		return nil, err
	}
	Inspect(s.Expr, func(node Node, path []Node) bool {
		var set storage.SeriesSet
		params := &storage.SelectParams{
			Step: int64(s.Interval / time.Millisecond),
		}
		switch n := node.(type) {
		case *VectorSelector:
			params.Func = extractFuncFromPath(path)
			set, err = querier.Select(params, n.LabelMatchers...)
			if err != nil {
				level.Error(ng.logger).Log("msg", "error selecting series set", "err", err)
				return false
			}
			n.series, err = expandSeriesSet(set)
			if err != nil {
				level.Error(ng.logger).Log("msg", "error expanding series set", "err", err)
				return false
			}
		case *MatrixSelector:
			params.Func = extractFuncFromPath(path)
			set, err = querier.Select(params, n.LabelMatchers...)
			if err != nil {
				level.Error(ng.logger).Log("msg", "error selecting series set", "err", err)
				return false
			}
			n.series, err = expandSeriesSet(set)
			if err != nil {
				level.Error(ng.logger).Log("msg", "error expanding series set", "err", err)
				return false
			}
		}
		return true
	})
	return querier, err
}
func extractFuncFromPath(p []Node) string {
	if len(p) == 0 {
		return ""
	}
	switch n := p[len(p)-1].(type) {
	case *AggregateExpr:
		return n.Op.String()
	case *Call:
		return n.Func.Name
	case *BinaryExpr:
		return ""
	}
	return extractFuncFromPath(p[:len(p)-1])
}
func expandSeriesSet(it storage.SeriesSet) (res []storage.Series, err error) {
	for it.Next() {
		res = append(res, it.At())
	}
	return res, it.Err()
}
type evaluator struct {
	ctx context.Context
	startTimestamp int64  
	endTimestamp int64  
	interval     int64  
	logger log.Logger
}
func (ev *evaluator) errorf(format string, args ...interface{}) {
	ev.error(fmt.Errorf(format, args...))
}
func (ev *evaluator) error(err error) {
	panic(err)
}
func (ev *evaluator) recover(errp *error) {
	e := recover()
	if e == nil {
		return
	}
	if err, ok := e.(runtime.Error); ok {
		buf := make([]byte, 64<<10)
		buf = buf[:runtime.Stack(buf, false)]
		level.Error(ev.logger).Log("msg", "runtime panic in parser", "err", e, "stacktrace", string(buf))
		*errp = fmt.Errorf("unexpected error: %s", err)
	} else {
		*errp = e.(error)
	}
}
func (ev *evaluator) Eval(expr Expr) (v Value, err error) {
	defer ev.recover(&err)
	return ev.eval(expr), nil
}
type EvalNodeHelper struct {
	ts int64
	out Vector
	dmn map[uint64]labels.Labels
	sigf map[uint64]uint64
	signatureToMetricWithBuckets map[uint64]*metricWithBuckets
	regex *regexp.Regexp
	rightSigs    map[uint64]Sample
	matchedSigs  map[uint64]map[uint64]struct{}
	resultMetric map[uint64]labels.Labels
}
func (enh *EvalNodeHelper) dropMetricName(l labels.Labels) labels.Labels {
	if enh.dmn == nil {
		enh.dmn = make(map[uint64]labels.Labels, len(enh.out))
	}
	h := l.Hash()
	ret, ok := enh.dmn[h]
	if ok {
		return ret
	}
	ret = dropMetricName(l)
	enh.dmn[h] = ret
	return ret
}
func (enh *EvalNodeHelper) signatureFunc(on bool, names ...string) func(labels.Labels) uint64 {
	if enh.sigf == nil {
		enh.sigf = make(map[uint64]uint64, len(enh.out))
	}
	f := signatureFunc(on, names...)
	return func(l labels.Labels) uint64 {
		h := l.Hash()
		ret, ok := enh.sigf[h]
		if ok {
			return ret
		}
		ret = f(l)
		enh.sigf[h] = ret
		return ret
	}
}
func (ev *evaluator) rangeEval(f func([]Value, *EvalNodeHelper) Vector, exprs ...Expr) Matrix {
	numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1
	matrixes := make([]Matrix, len(exprs))
	origMatrixes := make([]Matrix, len(exprs))
	for i, e := range exprs {
		if e != nil && e.Type() != ValueTypeString {
			matrixes[i] = ev.eval(e).(Matrix)
			origMatrixes[i] = make(Matrix, len(matrixes[i]))
			copy(origMatrixes[i], matrixes[i])
		}
	}
	vectors := make([]Vector, len(exprs))  
	args := make([]Value, len(exprs))      
	biggestLen := 1
	for i := range exprs {
		vectors[i] = make(Vector, 0, len(matrixes[i]))
		if len(matrixes[i]) > biggestLen {
			biggestLen = len(matrixes[i])
		}
	}
	enh := &EvalNodeHelper{out: make(Vector, 0, biggestLen)}
	seriess := make(map[uint64]Series, biggestLen)  
	for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval {
		for i := range exprs {
			vectors[i] = vectors[i][:0]
			for si, series := range matrixes[i] {
				for _, point := range series.Points {
					if point.T == ts {
						vectors[i] = append(vectors[i], Sample{Metric: series.Metric, Point: point})
						matrixes[i][si].Points = series.Points[1:]
					}
					break
				}
			}
			args[i] = vectors[i]
		}
		enh.ts = ts
		result := f(args, enh)
		enh.out = result[:0]  
		if ev.endTimestamp == ev.startTimestamp {
			mat := make(Matrix, len(result))
			for i, s := range result {
				s.Point.T = ts
				mat[i] = Series{Metric: s.Metric, Points: []Point{s.Point}}
			}
			return mat
		}
		for _, sample := range result {
			h := sample.Metric.Hash()
			ss, ok := seriess[h]
			if !ok {
				ss = Series{
					Metric: sample.Metric,
					Points: getPointSlice(numSteps),
				}
			}
			sample.Point.T = ts
			ss.Points = append(ss.Points, sample.Point)
			seriess[h] = ss
		}
	}
	for _, m := range origMatrixes {
		for _, s := range m {
			putPointSlice(s.Points)
		}
	}
	mat := make(Matrix, 0, len(seriess))
	for _, ss := range seriess {
		mat = append(mat, ss)
	}
	return mat
}