mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-25 13:44:05 -08:00
Proposal to improve FPointSlice and HPointSlice allocation. (#13448)
* Reusing points slice from previous series when the slice is under utilized * Adding comments on the bench test Signed-off-by: Alan Protasio <alanprot@gmail.com>
This commit is contained in:
parent
5f2c3a5d3e
commit
c006c57efc
|
@ -33,6 +33,10 @@ func setupRangeQueryTestData(stor *teststorage.TestStorage, _ *Engine, interval,
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
metrics := []labels.Labels{}
|
metrics := []labels.Labels{}
|
||||||
|
// Generating test series: a_X, b_X, and h_X, where X can take values of one, ten, or hundred,
|
||||||
|
// representing the number of series each metric name contains.
|
||||||
|
// Metric a_X and b_X are simple metrics where h_X is a histogram.
|
||||||
|
// These metrics will have data for all test time range
|
||||||
metrics = append(metrics, labels.FromStrings("__name__", "a_one"))
|
metrics = append(metrics, labels.FromStrings("__name__", "a_one"))
|
||||||
metrics = append(metrics, labels.FromStrings("__name__", "b_one"))
|
metrics = append(metrics, labels.FromStrings("__name__", "b_one"))
|
||||||
for j := 0; j < 10; j++ {
|
for j := 0; j < 10; j++ {
|
||||||
|
@ -59,6 +63,9 @@ func setupRangeQueryTestData(stor *teststorage.TestStorage, _ *Engine, interval,
|
||||||
}
|
}
|
||||||
refs := make([]storage.SeriesRef, len(metrics))
|
refs := make([]storage.SeriesRef, len(metrics))
|
||||||
|
|
||||||
|
// Number points for each different label value of "l" for the sparse series
|
||||||
|
pointsPerSparseSeries := numIntervals / 50
|
||||||
|
|
||||||
for s := 0; s < numIntervals; s++ {
|
for s := 0; s < numIntervals; s++ {
|
||||||
a := stor.Appender(context.Background())
|
a := stor.Appender(context.Background())
|
||||||
ts := int64(s * interval)
|
ts := int64(s * interval)
|
||||||
|
@ -66,10 +73,18 @@ func setupRangeQueryTestData(stor *teststorage.TestStorage, _ *Engine, interval,
|
||||||
ref, _ := a.Append(refs[i], metric, ts, float64(s)+float64(i)/float64(len(metrics)))
|
ref, _ := a.Append(refs[i], metric, ts, float64(s)+float64(i)/float64(len(metrics)))
|
||||||
refs[i] = ref
|
refs[i] = ref
|
||||||
}
|
}
|
||||||
|
// Generating a sparse time series: each label value of "l" will contain data only for
|
||||||
|
// pointsPerSparseSeries points
|
||||||
|
metric := labels.FromStrings("__name__", "sparse", "l", strconv.Itoa(s/pointsPerSparseSeries))
|
||||||
|
_, err := a.Append(0, metric, ts, float64(s)/float64(len(metrics)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := a.Commit(); err != nil {
|
if err := a.Commit(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stor.DB.ForceHeadMMap() // Ensure we have at most one head chunk for every series.
|
stor.DB.ForceHeadMMap() // Ensure we have at most one head chunk for every series.
|
||||||
stor.DB.Compact(ctx)
|
stor.DB.Compact(ctx)
|
||||||
return nil
|
return nil
|
||||||
|
@ -94,6 +109,10 @@ func rangeQueryCases() []benchCase {
|
||||||
expr: "rate(a_X[1m])",
|
expr: "rate(a_X[1m])",
|
||||||
steps: 10000,
|
steps: 10000,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
expr: "rate(sparse[1m])",
|
||||||
|
steps: 10000,
|
||||||
|
},
|
||||||
// Holt-Winters and long ranges.
|
// Holt-Winters and long ranges.
|
||||||
{
|
{
|
||||||
expr: "holt_winters(a_X[1d], 0.3, 0.3)",
|
expr: "holt_winters(a_X[1d], 0.3, 0.3)",
|
||||||
|
|
|
@ -1452,6 +1452,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio
|
||||||
// Reuse objects across steps to save memory allocations.
|
// Reuse objects across steps to save memory allocations.
|
||||||
var floats []FPoint
|
var floats []FPoint
|
||||||
var histograms []HPoint
|
var histograms []HPoint
|
||||||
|
var prevSS *Series
|
||||||
inMatrix := make(Matrix, 1)
|
inMatrix := make(Matrix, 1)
|
||||||
inArgs[matrixArgIndex] = inMatrix
|
inArgs[matrixArgIndex] = inMatrix
|
||||||
enh := &EvalNodeHelper{Out: make(Vector, 0, 1)}
|
enh := &EvalNodeHelper{Out: make(Vector, 0, 1)}
|
||||||
|
@ -1512,12 +1513,13 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio
|
||||||
if len(outVec) > 0 {
|
if len(outVec) > 0 {
|
||||||
if outVec[0].H == nil {
|
if outVec[0].H == nil {
|
||||||
if ss.Floats == nil {
|
if ss.Floats == nil {
|
||||||
ss.Floats = getFPointSlice(numSteps)
|
ss.Floats = reuseOrGetFPointSlices(prevSS, numSteps)
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.Floats = append(ss.Floats, FPoint{F: outVec[0].F, T: ts})
|
ss.Floats = append(ss.Floats, FPoint{F: outVec[0].F, T: ts})
|
||||||
} else {
|
} else {
|
||||||
if ss.Histograms == nil {
|
if ss.Histograms == nil {
|
||||||
ss.Histograms = getHPointSlice(numSteps)
|
ss.Histograms = reuseOrGetHPointSlices(prevSS, numSteps)
|
||||||
}
|
}
|
||||||
ss.Histograms = append(ss.Histograms, HPoint{H: outVec[0].H, T: ts})
|
ss.Histograms = append(ss.Histograms, HPoint{H: outVec[0].H, T: ts})
|
||||||
}
|
}
|
||||||
|
@ -1526,9 +1528,11 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio
|
||||||
it.ReduceDelta(stepRange)
|
it.ReduceDelta(stepRange)
|
||||||
}
|
}
|
||||||
histSamples := totalHPointSize(ss.Histograms)
|
histSamples := totalHPointSize(ss.Histograms)
|
||||||
|
|
||||||
if len(ss.Floats)+histSamples > 0 {
|
if len(ss.Floats)+histSamples > 0 {
|
||||||
if ev.currentSamples+len(ss.Floats)+histSamples <= ev.maxSamples {
|
if ev.currentSamples+len(ss.Floats)+histSamples <= ev.maxSamples {
|
||||||
mat = append(mat, ss)
|
mat = append(mat, ss)
|
||||||
|
prevSS = &mat[len(mat)-1]
|
||||||
ev.currentSamples += len(ss.Floats) + histSamples
|
ev.currentSamples += len(ss.Floats) + histSamples
|
||||||
} else {
|
} else {
|
||||||
ev.error(ErrTooManySamples(env))
|
ev.error(ErrTooManySamples(env))
|
||||||
|
@ -1678,6 +1682,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio
|
||||||
ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws})
|
ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws})
|
||||||
}
|
}
|
||||||
mat := make(Matrix, 0, len(e.Series))
|
mat := make(Matrix, 0, len(e.Series))
|
||||||
|
var prevSS *Series
|
||||||
it := storage.NewMemoizedEmptyIterator(durationMilliseconds(ev.lookbackDelta))
|
it := storage.NewMemoizedEmptyIterator(durationMilliseconds(ev.lookbackDelta))
|
||||||
var chkIter chunkenc.Iterator
|
var chkIter chunkenc.Iterator
|
||||||
for i, s := range e.Series {
|
for i, s := range e.Series {
|
||||||
|
@ -1697,14 +1702,14 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio
|
||||||
if ev.currentSamples < ev.maxSamples {
|
if ev.currentSamples < ev.maxSamples {
|
||||||
if h == nil {
|
if h == nil {
|
||||||
if ss.Floats == nil {
|
if ss.Floats == nil {
|
||||||
ss.Floats = getFPointSlice(numSteps)
|
ss.Floats = reuseOrGetFPointSlices(prevSS, numSteps)
|
||||||
}
|
}
|
||||||
ss.Floats = append(ss.Floats, FPoint{F: f, T: ts})
|
ss.Floats = append(ss.Floats, FPoint{F: f, T: ts})
|
||||||
ev.currentSamples++
|
ev.currentSamples++
|
||||||
ev.samplesStats.IncrementSamplesAtStep(step, 1)
|
ev.samplesStats.IncrementSamplesAtStep(step, 1)
|
||||||
} else {
|
} else {
|
||||||
if ss.Histograms == nil {
|
if ss.Histograms == nil {
|
||||||
ss.Histograms = getHPointSlice(numSteps)
|
ss.Histograms = reuseOrGetHPointSlices(prevSS, numSteps)
|
||||||
}
|
}
|
||||||
point := HPoint{H: h, T: ts}
|
point := HPoint{H: h, T: ts}
|
||||||
ss.Histograms = append(ss.Histograms, point)
|
ss.Histograms = append(ss.Histograms, point)
|
||||||
|
@ -1720,6 +1725,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio
|
||||||
|
|
||||||
if len(ss.Floats)+len(ss.Histograms) > 0 {
|
if len(ss.Floats)+len(ss.Histograms) > 0 {
|
||||||
mat = append(mat, ss)
|
mat = append(mat, ss)
|
||||||
|
prevSS = &mat[len(mat)-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ev.samplesStats.UpdatePeak(ev.currentSamples)
|
ev.samplesStats.UpdatePeak(ev.currentSamples)
|
||||||
|
@ -1840,6 +1846,30 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio
|
||||||
panic(fmt.Errorf("unhandled expression of type: %T", expr))
|
panic(fmt.Errorf("unhandled expression of type: %T", expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reuseOrGetFPointSlices reuses the space from previous slice to create new slice if the former has lots of room.
|
||||||
|
// The previous slices capacity is adjusted so when it is re-used from the pool it doesn't overflow into the new one.
|
||||||
|
func reuseOrGetHPointSlices(prevSS *Series, numSteps int) (r []HPoint) {
|
||||||
|
if prevSS != nil && cap(prevSS.Histograms)-2*len(prevSS.Histograms) > 0 {
|
||||||
|
r = prevSS.Histograms[len(prevSS.Histograms):]
|
||||||
|
prevSS.Histograms = prevSS.Histograms[0:len(prevSS.Histograms):len(prevSS.Histograms)]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHPointSlice(numSteps)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reuseOrGetFPointSlices reuses the space from previous slice to create new slice if the former has lots of room.
|
||||||
|
// The previous slices capacity is adjusted so when it is re-used from the pool it doesn't overflow into the new one.
|
||||||
|
func reuseOrGetFPointSlices(prevSS *Series, numSteps int) (r []FPoint) {
|
||||||
|
if prevSS != nil && cap(prevSS.Floats)-2*len(prevSS.Floats) > 0 {
|
||||||
|
r = prevSS.Floats[len(prevSS.Floats):]
|
||||||
|
prevSS.Floats = prevSS.Floats[0:len(prevSS.Floats):len(prevSS.Floats)]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return getFPointSlice(numSteps)
|
||||||
|
}
|
||||||
|
|
||||||
func (ev *evaluator) rangeEvalTimestampFunctionOverVectorSelector(vs *parser.VectorSelector, call FunctionCall, e *parser.Call) (parser.Value, annotations.Annotations) {
|
func (ev *evaluator) rangeEvalTimestampFunctionOverVectorSelector(vs *parser.VectorSelector, call FunctionCall, e *parser.Call) (parser.Value, annotations.Annotations) {
|
||||||
ws, err := checkAndExpandSeriesSet(ev.ctx, vs)
|
ws, err := checkAndExpandSeriesSet(ev.ctx, vs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue