Like Prometheus, but for logs.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
loki/pkg/logql/quantile_over_time_sketch.go

390 lines
9.9 KiB

package logql
import (
"fmt"
Benchmark and improve sketch join (#11534) **What this PR does / why we need it**: We saw that `JoinQuantileSketchVector` was using too much memory. This is a small step to improve the allocated memory. ``` pkg: github.com/grafana/loki/pkg/logql │ main.log │ pool.log │ │ sec/op │ sec/op vs base │ JoinQuantileSketchVector-10 3.603µ ± 4% 2.631µ ± 0% -26.99% (p=0.002 n=6) │ main.log │ pool.log │ │ B/op │ B/op vs base │ JoinQuantileSketchVector-10 8.344Ki ± 0% 2.539Ki ± 0% -69.57% (p=0.002 n=6) │ main.log │ pool.log │ │ allocs/op │ allocs/op vs base │ JoinQuantileSketchVector-10 109.0 ± 0% 104.0 ± 0% -4.59% (p=0.002 n=6) ``` **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] If the change is worth mentioning in the release notes, add `add-to-release-notes` label - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/setup/upgrade/_index.md` - [ ] For Helm chart changes bump the Helm chart version in `production/helm/loki/Chart.yaml` and update `production/helm/loki/CHANGELOG.md` and `production/helm/loki/README.md`. [Example PR](https://github.com/grafana/loki/commit/d10549e3ece02120974929894ee333d07755d213) - [ ] If the change is deprecating or removing a configuration option, update the `deprecated-config.yaml` and `deleted-config.yaml` files respectively in the `tools/deprecated-config-checker` directory. [Example PR](https://github.com/grafana/loki/pull/10840/commits/0d4416a4b03739583349934b96f272fb4f685d15) --------- Signed-off-by: Callum Styan <callumstyan@gmail.com> Co-authored-by: Callum Styan <callumstyan@gmail.com>
1 year ago
"math"
"sync"
"time"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql"
promql_parser "github.com/prometheus/prometheus/promql/parser"
"github.com/grafana/loki/v3/pkg/iter"
"github.com/grafana/loki/v3/pkg/logproto"
"github.com/grafana/loki/v3/pkg/logql/sketch"
"github.com/grafana/loki/v3/pkg/logqlmodel"
)
const (
QuantileSketchMatrixType = "QuantileSketchMatrix"
)
type (
ProbabilisticQuantileVector []ProbabilisticQuantileSample
ProbabilisticQuantileMatrix []ProbabilisticQuantileVector
)
var streamHashPool = sync.Pool{
New: func() interface{} { return make(map[uint64]int) },
}
func (q ProbabilisticQuantileVector) Merge(right ProbabilisticQuantileVector) (ProbabilisticQuantileVector, error) {
// labels hash to vector index map
groups := streamHashPool.Get().(map[uint64]int)
defer func() {
clear(groups)
streamHashPool.Put(groups)
}()
for i, sample := range q {
groups[sample.Metric.Hash()] = i
}
for _, sample := range right {
i, ok := groups[sample.Metric.Hash()]
if !ok {
q = append(q, sample)
continue
}
_, err := q[i].F.Merge(sample.F)
if err != nil {
return q, err
}
}
return q, nil
}
func (ProbabilisticQuantileVector) SampleVector() promql.Vector {
return promql.Vector{}
}
func (q ProbabilisticQuantileVector) QuantileSketchVec() ProbabilisticQuantileVector {
return q
}
func (q ProbabilisticQuantileVector) ToProto() *logproto.QuantileSketchVector {
samples := make([]*logproto.QuantileSketchSample, len(q))
for i, sample := range q {
samples[i] = sample.ToProto()
}
return &logproto.QuantileSketchVector{Samples: samples}
}
Change ddsketch mapping to improve performance. (#11561) **What this PR does / why we need it**: We've found that the index mapping of our quantile over time approximation has a big impact on the CPU. Changing the implementation gives us around 50%. The mapping is used during the `At` calls to the iterator. ``` › benchstat logarithmic.log cubic.log sort.log pool.log goos: linux goarch: amd64 pkg: github.com/grafana/loki/pkg/logql cpu: AMD Ryzen 7 3700X 8-Core Processor │ logarithmic.log │ cubic.log │ sort.log │ pool.log │ │ sec/op │ sec/op vs base │ sec/op vs base │ sec/op vs base │ QuantileBatchRangeVectorIteratorAt/1-samples-16 819.7n ± 2% 1052.5n ± 5% +28.40% (p=0.002 n=6) 1055.0n ± 1% +28.71% (p=0.002 n=6) 303.7n ± 4% -62.96% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/1000-samples-16 60.34µ ± 8% 49.32µ ± 13% -18.26% (p=0.002 n=6) 45.94µ ± 4% -23.86% (p=0.002 n=6) 24.97µ ± 3% -58.61% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/100000-samples-16 3.032m ± 3% 1.319m ± 1% -56.50% (p=0.002 n=6) 1.316m ± 4% -56.58% (p=0.002 n=6) 1.278m ± 3% -57.86% (p=0.002 n=6) geomean 53.13µ 40.91µ -23.00% 39.96µ -24.79% 21.32µ -59.87% │ logarithmic.log │ cubic.log │ sort.log │ pool.log │ │ B/op │ B/op vs base │ B/op vs base │ B/op vs base │ QuantileBatchRangeVectorIteratorAt/1-samples-16 368.00 ± 0% 368.00 ± 0% ~ (p=1.000 n=6) ¹ 368.00 ± 0% ~ (p=1.000 n=6) ¹ 32.00 ± 0% -91.30% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/1000-samples-16 4048.0 ± 0% 4048.0 ± 0% ~ (p=1.000 n=6) ¹ 3920.0 ± 0% -3.16% (p=0.002 n=6) 104.0 ± 0% -97.43% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/100000-samples-16 6192.0 ± 0% 6192.0 ± 0% ~ (p=1.000 n=6) ¹ 5936.0 ± 0% -4.13% (p=0.002 n=6) 202.0 ± 5% -96.74% (p=0.002 n=6) geomean 2.048Ki 2.048Ki +0.00% 1.998Ki -2.45% 87.60 -95.82% ¹ all samples are equal │ logarithmic.log │ cubic.log │ sort.log │ pool.log │ │ allocs/op │ allocs/op vs base │ allocs/op vs base │ allocs/op vs base │ QuantileBatchRangeVectorIteratorAt/1-samples-16 8.000 ± 0% 8.000 ± 0% ~ (p=1.000 n=6) ¹ 8.000 ± 0% ~ (p=1.000 n=6) ¹ 2.000 ± 0% -75.00% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/1000-samples-16 27.000 ± 0% 27.000 ± 0% ~ (p=1.000 n=6) ¹ 23.000 ± 0% -14.81% (p=0.002 n=6) 5.000 ± 0% -81.48% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/100000-samples-16 42.000 ± 0% 42.000 ± 0% ~ (p=1.000 n=6) ¹ 34.000 ± 0% -19.05% (p=0.002 n=6) 9.000 ± 0% -78.57% (p=0.002 n=6) geomean 20.86 20.86 +0.00% 18.43 -11.65% 4.481 -78.51% ¹ all samples are equal ``` **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [x] Tests updated - [ ] `CHANGELOG.md` updated - [ ] If the change is worth mentioning in the release notes, add `add-to-release-notes` label - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/setup/upgrade/_index.md` - [ ] For Helm chart changes bump the Helm chart version in `production/helm/loki/Chart.yaml` and update `production/helm/loki/CHANGELOG.md` and `production/helm/loki/README.md`. [Example PR](https://github.com/grafana/loki/commit/d10549e3ece02120974929894ee333d07755d213) - [ ] If the change is deprecating or removing a configuration option, update the `deprecated-config.yaml` and `deleted-config.yaml` files respectively in the `tools/deprecated-config-checker` directory. [Example PR](https://github.com/grafana/loki/pull/10840/commits/0d4416a4b03739583349934b96f272fb4f685d15)
1 year ago
func (q ProbabilisticQuantileVector) Release() {
for _, s := range q {
s.F.Release()
}
}
func ProbabilisticQuantileVectorFromProto(proto *logproto.QuantileSketchVector) (ProbabilisticQuantileVector, error) {
out := make([]ProbabilisticQuantileSample, len(proto.Samples))
var s ProbabilisticQuantileSample
var err error
for i, sample := range proto.Samples {
s, err = probabilisticQuantileSampleFromProto(sample)
if err != nil {
return ProbabilisticQuantileVector{}, err
}
out[i] = s
}
return out, nil
}
func (ProbabilisticQuantileMatrix) String() string {
return "QuantileSketchMatrix()"
}
func (m ProbabilisticQuantileMatrix) Merge(right ProbabilisticQuantileMatrix) (ProbabilisticQuantileMatrix, error) {
if len(m) != len(right) {
return nil, fmt.Errorf("failed to merge probabilistic quantile matrix: lengths differ %d!=%d", len(m), len(right))
}
var err error
for i, vec := range m {
m[i], err = vec.Merge(right[i])
if err != nil {
return nil, fmt.Errorf("failed to merge probabilistic quantile matrix: %w", err)
}
}
return m, nil
}
func (ProbabilisticQuantileMatrix) Type() promql_parser.ValueType { return QuantileSketchMatrixType }
Benchmark and improve sketch join (#11534) **What this PR does / why we need it**: We saw that `JoinQuantileSketchVector` was using too much memory. This is a small step to improve the allocated memory. ``` pkg: github.com/grafana/loki/pkg/logql │ main.log │ pool.log │ │ sec/op │ sec/op vs base │ JoinQuantileSketchVector-10 3.603µ ± 4% 2.631µ ± 0% -26.99% (p=0.002 n=6) │ main.log │ pool.log │ │ B/op │ B/op vs base │ JoinQuantileSketchVector-10 8.344Ki ± 0% 2.539Ki ± 0% -69.57% (p=0.002 n=6) │ main.log │ pool.log │ │ allocs/op │ allocs/op vs base │ JoinQuantileSketchVector-10 109.0 ± 0% 104.0 ± 0% -4.59% (p=0.002 n=6) ``` **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] If the change is worth mentioning in the release notes, add `add-to-release-notes` label - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/setup/upgrade/_index.md` - [ ] For Helm chart changes bump the Helm chart version in `production/helm/loki/Chart.yaml` and update `production/helm/loki/CHANGELOG.md` and `production/helm/loki/README.md`. [Example PR](https://github.com/grafana/loki/commit/d10549e3ece02120974929894ee333d07755d213) - [ ] If the change is deprecating or removing a configuration option, update the `deprecated-config.yaml` and `deleted-config.yaml` files respectively in the `tools/deprecated-config-checker` directory. [Example PR](https://github.com/grafana/loki/pull/10840/commits/0d4416a4b03739583349934b96f272fb4f685d15) --------- Signed-off-by: Callum Styan <callumstyan@gmail.com> Co-authored-by: Callum Styan <callumstyan@gmail.com>
1 year ago
func (m ProbabilisticQuantileMatrix) Release() {
Change ddsketch mapping to improve performance. (#11561) **What this PR does / why we need it**: We've found that the index mapping of our quantile over time approximation has a big impact on the CPU. Changing the implementation gives us around 50%. The mapping is used during the `At` calls to the iterator. ``` › benchstat logarithmic.log cubic.log sort.log pool.log goos: linux goarch: amd64 pkg: github.com/grafana/loki/pkg/logql cpu: AMD Ryzen 7 3700X 8-Core Processor │ logarithmic.log │ cubic.log │ sort.log │ pool.log │ │ sec/op │ sec/op vs base │ sec/op vs base │ sec/op vs base │ QuantileBatchRangeVectorIteratorAt/1-samples-16 819.7n ± 2% 1052.5n ± 5% +28.40% (p=0.002 n=6) 1055.0n ± 1% +28.71% (p=0.002 n=6) 303.7n ± 4% -62.96% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/1000-samples-16 60.34µ ± 8% 49.32µ ± 13% -18.26% (p=0.002 n=6) 45.94µ ± 4% -23.86% (p=0.002 n=6) 24.97µ ± 3% -58.61% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/100000-samples-16 3.032m ± 3% 1.319m ± 1% -56.50% (p=0.002 n=6) 1.316m ± 4% -56.58% (p=0.002 n=6) 1.278m ± 3% -57.86% (p=0.002 n=6) geomean 53.13µ 40.91µ -23.00% 39.96µ -24.79% 21.32µ -59.87% │ logarithmic.log │ cubic.log │ sort.log │ pool.log │ │ B/op │ B/op vs base │ B/op vs base │ B/op vs base │ QuantileBatchRangeVectorIteratorAt/1-samples-16 368.00 ± 0% 368.00 ± 0% ~ (p=1.000 n=6) ¹ 368.00 ± 0% ~ (p=1.000 n=6) ¹ 32.00 ± 0% -91.30% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/1000-samples-16 4048.0 ± 0% 4048.0 ± 0% ~ (p=1.000 n=6) ¹ 3920.0 ± 0% -3.16% (p=0.002 n=6) 104.0 ± 0% -97.43% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/100000-samples-16 6192.0 ± 0% 6192.0 ± 0% ~ (p=1.000 n=6) ¹ 5936.0 ± 0% -4.13% (p=0.002 n=6) 202.0 ± 5% -96.74% (p=0.002 n=6) geomean 2.048Ki 2.048Ki +0.00% 1.998Ki -2.45% 87.60 -95.82% ¹ all samples are equal │ logarithmic.log │ cubic.log │ sort.log │ pool.log │ │ allocs/op │ allocs/op vs base │ allocs/op vs base │ allocs/op vs base │ QuantileBatchRangeVectorIteratorAt/1-samples-16 8.000 ± 0% 8.000 ± 0% ~ (p=1.000 n=6) ¹ 8.000 ± 0% ~ (p=1.000 n=6) ¹ 2.000 ± 0% -75.00% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/1000-samples-16 27.000 ± 0% 27.000 ± 0% ~ (p=1.000 n=6) ¹ 23.000 ± 0% -14.81% (p=0.002 n=6) 5.000 ± 0% -81.48% (p=0.002 n=6) QuantileBatchRangeVectorIteratorAt/100000-samples-16 42.000 ± 0% 42.000 ± 0% ~ (p=1.000 n=6) ¹ 34.000 ± 0% -19.05% (p=0.002 n=6) 9.000 ± 0% -78.57% (p=0.002 n=6) geomean 20.86 20.86 +0.00% 18.43 -11.65% 4.481 -78.51% ¹ all samples are equal ``` **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [x] Tests updated - [ ] `CHANGELOG.md` updated - [ ] If the change is worth mentioning in the release notes, add `add-to-release-notes` label - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/setup/upgrade/_index.md` - [ ] For Helm chart changes bump the Helm chart version in `production/helm/loki/Chart.yaml` and update `production/helm/loki/CHANGELOG.md` and `production/helm/loki/README.md`. [Example PR](https://github.com/grafana/loki/commit/d10549e3ece02120974929894ee333d07755d213) - [ ] If the change is deprecating or removing a configuration option, update the `deprecated-config.yaml` and `deleted-config.yaml` files respectively in the `tools/deprecated-config-checker` directory. [Example PR](https://github.com/grafana/loki/pull/10840/commits/0d4416a4b03739583349934b96f272fb4f685d15)
1 year ago
for _, vec := range m {
vec.Release()
}
Benchmark and improve sketch join (#11534) **What this PR does / why we need it**: We saw that `JoinQuantileSketchVector` was using too much memory. This is a small step to improve the allocated memory. ``` pkg: github.com/grafana/loki/pkg/logql │ main.log │ pool.log │ │ sec/op │ sec/op vs base │ JoinQuantileSketchVector-10 3.603µ ± 4% 2.631µ ± 0% -26.99% (p=0.002 n=6) │ main.log │ pool.log │ │ B/op │ B/op vs base │ JoinQuantileSketchVector-10 8.344Ki ± 0% 2.539Ki ± 0% -69.57% (p=0.002 n=6) │ main.log │ pool.log │ │ allocs/op │ allocs/op vs base │ JoinQuantileSketchVector-10 109.0 ± 0% 104.0 ± 0% -4.59% (p=0.002 n=6) ``` **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] If the change is worth mentioning in the release notes, add `add-to-release-notes` label - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/setup/upgrade/_index.md` - [ ] For Helm chart changes bump the Helm chart version in `production/helm/loki/Chart.yaml` and update `production/helm/loki/CHANGELOG.md` and `production/helm/loki/README.md`. [Example PR](https://github.com/grafana/loki/commit/d10549e3ece02120974929894ee333d07755d213) - [ ] If the change is deprecating or removing a configuration option, update the `deprecated-config.yaml` and `deleted-config.yaml` files respectively in the `tools/deprecated-config-checker` directory. [Example PR](https://github.com/grafana/loki/pull/10840/commits/0d4416a4b03739583349934b96f272fb4f685d15) --------- Signed-off-by: Callum Styan <callumstyan@gmail.com> Co-authored-by: Callum Styan <callumstyan@gmail.com>
1 year ago
}
func (m ProbabilisticQuantileMatrix) ToProto() *logproto.QuantileSketchMatrix {
values := make([]*logproto.QuantileSketchVector, len(m))
for i, vec := range m {
values[i] = vec.ToProto()
}
return &logproto.QuantileSketchMatrix{Values: values}
}
func ProbabilisticQuantileMatrixFromProto(proto *logproto.QuantileSketchMatrix) (ProbabilisticQuantileMatrix, error) {
out := make([]ProbabilisticQuantileVector, len(proto.Values))
var s ProbabilisticQuantileVector
var err error
for i, v := range proto.Values {
s, err = ProbabilisticQuantileVectorFromProto(v)
if err != nil {
return ProbabilisticQuantileMatrix{}, err
}
out[i] = s
}
return out, nil
}
type QuantileSketchStepEvaluator struct {
iter RangeVectorIterator
err error
}
func (e *QuantileSketchStepEvaluator) Next() (bool, int64, StepResult) {
next := e.iter.Next()
if !next {
return false, 0, ProbabilisticQuantileVector{}
}
ts, r := e.iter.At()
vec := r.QuantileSketchVec()
for _, s := range vec {
// Errors are not allowed in metrics unless they've been specifically requested.
if s.Metric.Has(logqlmodel.ErrorLabel) && s.Metric.Get(logqlmodel.PreserveErrorLabel) != "true" {
e.err = logqlmodel.NewPipelineErr(s.Metric)
return false, 0, ProbabilisticQuantileVector{}
}
}
return true, ts, vec
}
func (e *QuantileSketchStepEvaluator) Close() error { return e.iter.Close() }
func (e *QuantileSketchStepEvaluator) Error() error {
if e.err != nil {
return e.err
}
return e.iter.Error()
}
func (e *QuantileSketchStepEvaluator) Explain(parent Node) {
parent.Child("QuantileSketch")
}
func newQuantileSketchIterator(
it iter.PeekingSampleIterator,
selRange, step, start, end, offset int64,
) RangeVectorIterator {
inner := &batchRangeVectorIterator{
iter: it,
step: step,
end: end,
selRange: selRange,
metrics: map[string]labels.Labels{},
window: map[string]*promql.Series{},
agg: nil,
current: start - step, // first loop iteration will set it to start
offset: offset,
}
return &quantileSketchBatchRangeVectorIterator{
batchRangeVectorIterator: inner,
}
}
type ProbabilisticQuantileSample struct {
T int64
F sketch.QuantileSketch
Metric labels.Labels
}
func (q ProbabilisticQuantileSample) ToProto() *logproto.QuantileSketchSample {
metric := make([]*logproto.LabelPair, len(q.Metric))
for i, m := range q.Metric {
metric[i] = &logproto.LabelPair{Name: m.Name, Value: m.Value}
}
sketch := q.F.ToProto()
return &logproto.QuantileSketchSample{
F: sketch,
TimestampMs: q.T,
Metric: metric,
}
}
func probabilisticQuantileSampleFromProto(proto *logproto.QuantileSketchSample) (ProbabilisticQuantileSample, error) {
s, err := sketch.QuantileSketchFromProto(proto.F)
if err != nil {
return ProbabilisticQuantileSample{}, err
}
out := ProbabilisticQuantileSample{
T: proto.TimestampMs,
F: s,
Metric: make(labels.Labels, len(proto.Metric)),
}
for i, p := range proto.Metric {
out.Metric[i] = labels.Label{Name: p.Name, Value: p.Value}
}
return out, nil
}
type quantileSketchBatchRangeVectorIterator struct {
*batchRangeVectorIterator
}
func (r *quantileSketchBatchRangeVectorIterator) At() (int64, StepResult) {
at := make([]ProbabilisticQuantileSample, 0, len(r.window))
// convert ts from nano to milli seconds as the iterator work with nanoseconds
ts := r.current/1e+6 + r.offset/1e+6
for _, series := range r.window {
at = append(at, ProbabilisticQuantileSample{
F: r.agg(series.Floats),
T: ts,
Metric: series.Metric,
})
}
return ts, ProbabilisticQuantileVector(at)
}
func (r *quantileSketchBatchRangeVectorIterator) agg(samples []promql.FPoint) sketch.QuantileSketch {
s := sketch.NewDDSketch()
for _, v := range samples {
// The sketch from the underlying sketch package we are using
// cannot return an error when calling Add.
s.Add(v.F) //nolint:errcheck
}
return s
}
// MergeQuantileSketchVector joins the results from stepEvaluator into a ProbabilisticQuantileMatrix.
func MergeQuantileSketchVector(next bool, r StepResult, stepEvaluator StepEvaluator, params Params) (promql_parser.Value, error) {
vec := r.QuantileSketchVec()
if stepEvaluator.Error() != nil {
return nil, stepEvaluator.Error()
}
if GetRangeType(params) == InstantType {
return ProbabilisticQuantileMatrix{vec}, nil
}
Benchmark and improve sketch join (#11534) **What this PR does / why we need it**: We saw that `JoinQuantileSketchVector` was using too much memory. This is a small step to improve the allocated memory. ``` pkg: github.com/grafana/loki/pkg/logql │ main.log │ pool.log │ │ sec/op │ sec/op vs base │ JoinQuantileSketchVector-10 3.603µ ± 4% 2.631µ ± 0% -26.99% (p=0.002 n=6) │ main.log │ pool.log │ │ B/op │ B/op vs base │ JoinQuantileSketchVector-10 8.344Ki ± 0% 2.539Ki ± 0% -69.57% (p=0.002 n=6) │ main.log │ pool.log │ │ allocs/op │ allocs/op vs base │ JoinQuantileSketchVector-10 109.0 ± 0% 104.0 ± 0% -4.59% (p=0.002 n=6) ``` **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] If the change is worth mentioning in the release notes, add `add-to-release-notes` label - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/setup/upgrade/_index.md` - [ ] For Helm chart changes bump the Helm chart version in `production/helm/loki/Chart.yaml` and update `production/helm/loki/CHANGELOG.md` and `production/helm/loki/README.md`. [Example PR](https://github.com/grafana/loki/commit/d10549e3ece02120974929894ee333d07755d213) - [ ] If the change is deprecating or removing a configuration option, update the `deprecated-config.yaml` and `deleted-config.yaml` files respectively in the `tools/deprecated-config-checker` directory. [Example PR](https://github.com/grafana/loki/pull/10840/commits/0d4416a4b03739583349934b96f272fb4f685d15) --------- Signed-off-by: Callum Styan <callumstyan@gmail.com> Co-authored-by: Callum Styan <callumstyan@gmail.com>
1 year ago
stepCount := int(math.Ceil(float64(params.End().Sub(params.Start()).Nanoseconds()) / float64(params.Step().Nanoseconds())))
if stepCount <= 0 {
stepCount = 1
}
result := make(ProbabilisticQuantileMatrix, 0, stepCount)
for next {
result = append(result, vec)
next, _, r = stepEvaluator.Next()
vec = r.QuantileSketchVec()
if stepEvaluator.Error() != nil {
return nil, stepEvaluator.Error()
}
}
return result, stepEvaluator.Error()
}
// QuantileSketchMatrixStepEvaluator steps through a matrix of quantile sketch
// vectors, ie t-digest or DDSketch structures per time step.
type QuantileSketchMatrixStepEvaluator struct {
start, end, ts time.Time
step time.Duration
m ProbabilisticQuantileMatrix
}
func NewQuantileSketchMatrixStepEvaluator(m ProbabilisticQuantileMatrix, params Params) *QuantileSketchMatrixStepEvaluator {
var (
start = params.Start()
end = params.End()
step = params.Step()
)
return &QuantileSketchMatrixStepEvaluator{
start: start,
end: end,
ts: start.Add(-step), // will be corrected on first Next() call
step: step,
m: m,
}
}
func (m *QuantileSketchMatrixStepEvaluator) Next() (bool, int64, StepResult) {
m.ts = m.ts.Add(m.step)
if m.ts.After(m.end) {
return false, 0, nil
}
ts := m.ts.UnixNano() / int64(time.Millisecond)
if len(m.m) == 0 {
return false, 0, nil
}
vec := m.m[0]
// Reset for next step
m.m = m.m[1:]
return true, ts, vec
}
func (*QuantileSketchMatrixStepEvaluator) Close() error { return nil }
func (*QuantileSketchMatrixStepEvaluator) Error() error { return nil }
func (*QuantileSketchMatrixStepEvaluator) Explain(parent Node) {
parent.Child("QuantileSketchMatrix")
}
// QuantileSketchVectorStepEvaluator evaluates a quantile sketch into a
// promql.Vector.
type QuantileSketchVectorStepEvaluator struct {
inner StepEvaluator
quantile float64
}
var _ StepEvaluator = NewQuantileSketchVectorStepEvaluator(nil, 0)
func NewQuantileSketchVectorStepEvaluator(inner StepEvaluator, quantile float64) *QuantileSketchVectorStepEvaluator {
return &QuantileSketchVectorStepEvaluator{
inner: inner,
quantile: quantile,
}
}
func (e *QuantileSketchVectorStepEvaluator) Next() (bool, int64, StepResult) {
ok, ts, r := e.inner.Next()
if !ok {
return false, 0, SampleVector{}
}
quantileSketchVec := r.QuantileSketchVec()
vec := make(promql.Vector, len(quantileSketchVec))
for i, quantileSketch := range quantileSketchVec {
f, _ := quantileSketch.F.Quantile(e.quantile)
vec[i] = promql.Sample{
T: quantileSketch.T,
F: f,
Metric: quantileSketch.Metric,
}
}
return ok, ts, SampleVector(vec)
}
func (*QuantileSketchVectorStepEvaluator) Close() error { return nil }
func (*QuantileSketchVectorStepEvaluator) Error() error { return nil }