Optimize PromQL aggregations (#4248)
* Compute hash of label subsets without creating a LabelSet first. Signed-off-by: Alin Sinpalean <alin.sinpalean@gmail.com>
This commit is contained in:
parent
9e3171f6e3
commit
96fb0b2155
|
@ -94,6 +94,47 @@ func (ls Labels) Hash() uint64 {
|
||||||
return xxhash.Sum64(b)
|
return xxhash.Sum64(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HashForLabels returns a hash value for the labels matching the provided names.
|
||||||
|
func (ls Labels) HashForLabels(names ...string) uint64 {
|
||||||
|
b := make([]byte, 0, 1024)
|
||||||
|
|
||||||
|
for _, v := range ls {
|
||||||
|
for _, n := range names {
|
||||||
|
if v.Name == n {
|
||||||
|
b = append(b, v.Name...)
|
||||||
|
b = append(b, sep)
|
||||||
|
b = append(b, v.Value...)
|
||||||
|
b = append(b, sep)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xxhash.Sum64(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashWithoutLabels returns a hash value for all labels except those matching
|
||||||
|
// the provided names.
|
||||||
|
func (ls Labels) HashWithoutLabels(names ...string) uint64 {
|
||||||
|
b := make([]byte, 0, 1024)
|
||||||
|
|
||||||
|
Outer:
|
||||||
|
for _, v := range ls {
|
||||||
|
if v.Name == MetricName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, n := range names {
|
||||||
|
if v.Name == n {
|
||||||
|
continue Outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = append(b, v.Name...)
|
||||||
|
b = append(b, sep)
|
||||||
|
b = append(b, v.Value...)
|
||||||
|
b = append(b, sep)
|
||||||
|
}
|
||||||
|
return xxhash.Sum64(b)
|
||||||
|
}
|
||||||
|
|
||||||
// Copy returns a copy of the labels.
|
// Copy returns a copy of the labels.
|
||||||
func (ls Labels) Copy() Labels {
|
func (ls Labels) Copy() Labels {
|
||||||
res := make(Labels, len(ls))
|
res := make(Labels, len(ls))
|
||||||
|
|
|
@ -131,6 +131,22 @@ func BenchmarkRangeQuery(b *testing.B) {
|
||||||
{
|
{
|
||||||
expr: "label_join(a_X, 'l2', '-', 'l', 'l')",
|
expr: "label_join(a_X, 'l2', '-', 'l', 'l')",
|
||||||
},
|
},
|
||||||
|
// Simple aggregations.
|
||||||
|
{
|
||||||
|
expr: "sum(a_X)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: "sum without (l)(h_X)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: "sum without (le)(h_X)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: "sum by (l)(h_X)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: "sum by (le)(h_X)",
|
||||||
|
},
|
||||||
// Combinations.
|
// Combinations.
|
||||||
{
|
{
|
||||||
expr: "rate(a_X[1m]) + rate(b_X[1m])",
|
expr: "rate(a_X[1m]) + rate(b_X[1m])",
|
||||||
|
|
|
@ -1261,39 +1261,6 @@ func (ev *evaluator) VectorBinop(op ItemType, lhs, rhs Vector, matching *VectorM
|
||||||
return enh.out
|
return enh.out
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashWithoutLabels(lset labels.Labels, names ...string) uint64 {
|
|
||||||
cm := make(labels.Labels, 0, len(lset))
|
|
||||||
|
|
||||||
Outer:
|
|
||||||
for _, l := range lset {
|
|
||||||
for _, n := range names {
|
|
||||||
if n == l.Name {
|
|
||||||
continue Outer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if l.Name == labels.MetricName {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cm = append(cm, l)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cm.Hash()
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashForLabels(lset labels.Labels, names ...string) uint64 {
|
|
||||||
cm := make(labels.Labels, 0, len(names))
|
|
||||||
|
|
||||||
for _, l := range lset {
|
|
||||||
for _, n := range names {
|
|
||||||
if l.Name == n {
|
|
||||||
cm = append(cm, l)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cm.Hash()
|
|
||||||
}
|
|
||||||
|
|
||||||
// signatureFunc returns a function that calculates the signature for a metric
|
// signatureFunc returns a function that calculates the signature for a metric
|
||||||
// ignoring the provided labels. If on, then the given labels are only used instead.
|
// ignoring the provided labels. If on, then the given labels are only used instead.
|
||||||
func signatureFunc(on bool, names ...string) func(labels.Labels) uint64 {
|
func signatureFunc(on bool, names ...string) func(labels.Labels) uint64 {
|
||||||
|
@ -1301,9 +1268,9 @@ func signatureFunc(on bool, names ...string) func(labels.Labels) uint64 {
|
||||||
// of labels by names to speed up the operations below.
|
// of labels by names to speed up the operations below.
|
||||||
// Alternatively, inline the hashing and don't build new label sets.
|
// Alternatively, inline the hashing and don't build new label sets.
|
||||||
if on {
|
if on {
|
||||||
return func(lset labels.Labels) uint64 { return hashForLabels(lset, names...) }
|
return func(lset labels.Labels) uint64 { return lset.HashForLabels(names...) }
|
||||||
}
|
}
|
||||||
return func(lset labels.Labels) uint64 { return hashWithoutLabels(lset, names...) }
|
return func(lset labels.Labels) uint64 { return lset.HashWithoutLabels(names...) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// resultMetric returns the metric for the given sample(s) based on the Vector
|
// resultMetric returns the metric for the given sample(s) based on the Vector
|
||||||
|
@ -1504,24 +1471,21 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range vec {
|
for _, s := range vec {
|
||||||
lb := labels.NewBuilder(s.Metric)
|
metric := s.Metric
|
||||||
|
|
||||||
if without {
|
|
||||||
lb.Del(grouping...)
|
|
||||||
lb.Del(labels.MetricName)
|
|
||||||
}
|
|
||||||
if op == itemCountValues {
|
if op == itemCountValues {
|
||||||
|
lb := labels.NewBuilder(metric)
|
||||||
lb.Set(valueLabel, strconv.FormatFloat(s.V, 'f', -1, 64))
|
lb.Set(valueLabel, strconv.FormatFloat(s.V, 'f', -1, 64))
|
||||||
|
metric = lb.Labels()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
groupingKey uint64
|
groupingKey uint64
|
||||||
metric = lb.Labels()
|
|
||||||
)
|
)
|
||||||
if without {
|
if without {
|
||||||
groupingKey = metric.Hash()
|
groupingKey = metric.HashWithoutLabels(grouping...)
|
||||||
} else {
|
} else {
|
||||||
groupingKey = hashForLabels(metric, grouping...)
|
groupingKey = metric.HashForLabels(grouping...)
|
||||||
}
|
}
|
||||||
|
|
||||||
group, ok := result[groupingKey]
|
group, ok := result[groupingKey]
|
||||||
|
@ -1530,13 +1494,16 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
var m labels.Labels
|
var m labels.Labels
|
||||||
|
|
||||||
if without {
|
if without {
|
||||||
m = metric
|
lb := labels.NewBuilder(metric)
|
||||||
|
lb.Del(grouping...)
|
||||||
|
lb.Del(labels.MetricName)
|
||||||
|
m = lb.Labels()
|
||||||
} else {
|
} else {
|
||||||
m = make(labels.Labels, 0, len(grouping))
|
m = make(labels.Labels, 0, len(grouping))
|
||||||
for _, l := range metric {
|
for _, l := range metric {
|
||||||
for _, n := range grouping {
|
for _, n := range grouping {
|
||||||
if l.Name == n {
|
if l.Name == n {
|
||||||
m = append(m, labels.Label{Name: n, Value: l.Value})
|
m = append(m, l)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue