Merge pull request #13191 from linasm/reduceResolution-inplace

Reuse receiver slices in [Float]Histogram.ReduceResolution
This commit is contained in:
Björn Rabenstein 2023-11-28 17:48:52 +01:00 committed by GitHub
commit 97f9ad9d31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 13 deletions

View file

@ -94,8 +94,8 @@ func (h *FloatHistogram) CopyToSchema(targetSchema int32) *FloatHistogram {
Sum: h.Sum, Sum: h.Sum,
} }
c.PositiveSpans, c.PositiveBuckets = reduceResolution(h.PositiveSpans, h.PositiveBuckets, h.Schema, targetSchema, false) c.PositiveSpans, c.PositiveBuckets = reduceResolution(h.PositiveSpans, h.PositiveBuckets, h.Schema, targetSchema, false, false)
c.NegativeSpans, c.NegativeBuckets = reduceResolution(h.NegativeSpans, h.NegativeBuckets, h.Schema, targetSchema, false) c.NegativeSpans, c.NegativeBuckets = reduceResolution(h.NegativeSpans, h.NegativeBuckets, h.Schema, targetSchema, false, false)
return &c return &c
} }
@ -278,8 +278,8 @@ func (h *FloatHistogram) Add(other *FloatHistogram) *FloatHistogram {
if other.Schema < h.Schema { if other.Schema < h.Schema {
panic(fmt.Errorf("cannot add histogram with schema %d to %d", other.Schema, h.Schema)) panic(fmt.Errorf("cannot add histogram with schema %d to %d", other.Schema, h.Schema))
} else if other.Schema > h.Schema { } else if other.Schema > h.Schema {
otherPositiveSpans, otherPositiveBuckets = reduceResolution(otherPositiveSpans, otherPositiveBuckets, other.Schema, h.Schema, false) otherPositiveSpans, otherPositiveBuckets = reduceResolution(otherPositiveSpans, otherPositiveBuckets, other.Schema, h.Schema, false, false)
otherNegativeSpans, otherNegativeBuckets = reduceResolution(otherNegativeSpans, otherNegativeBuckets, other.Schema, h.Schema, false) otherNegativeSpans, otherNegativeBuckets = reduceResolution(otherNegativeSpans, otherNegativeBuckets, other.Schema, h.Schema, false, false)
} }
h.PositiveSpans, h.PositiveBuckets = addBuckets(h.Schema, h.ZeroThreshold, false, h.PositiveSpans, h.PositiveBuckets, otherPositiveSpans, otherPositiveBuckets) h.PositiveSpans, h.PositiveBuckets = addBuckets(h.Schema, h.ZeroThreshold, false, h.PositiveSpans, h.PositiveBuckets, otherPositiveSpans, otherPositiveBuckets)
@ -305,8 +305,8 @@ func (h *FloatHistogram) Sub(other *FloatHistogram) *FloatHistogram {
if other.Schema < h.Schema { if other.Schema < h.Schema {
panic(fmt.Errorf("cannot subtract histigram with schema %d to %d", other.Schema, h.Schema)) panic(fmt.Errorf("cannot subtract histigram with schema %d to %d", other.Schema, h.Schema))
} else if other.Schema > h.Schema { } else if other.Schema > h.Schema {
otherPositiveSpans, otherPositiveBuckets = reduceResolution(otherPositiveSpans, otherPositiveBuckets, other.Schema, h.Schema, false) otherPositiveSpans, otherPositiveBuckets = reduceResolution(otherPositiveSpans, otherPositiveBuckets, other.Schema, h.Schema, false, false)
otherNegativeSpans, otherNegativeBuckets = reduceResolution(otherNegativeSpans, otherNegativeBuckets, other.Schema, h.Schema, false) otherNegativeSpans, otherNegativeBuckets = reduceResolution(otherNegativeSpans, otherNegativeBuckets, other.Schema, h.Schema, false, false)
} }
h.PositiveSpans, h.PositiveBuckets = addBuckets(h.Schema, h.ZeroThreshold, true, h.PositiveSpans, h.PositiveBuckets, otherPositiveSpans, otherPositiveBuckets) h.PositiveSpans, h.PositiveBuckets = addBuckets(h.Schema, h.ZeroThreshold, true, h.PositiveSpans, h.PositiveBuckets, otherPositiveSpans, otherPositiveBuckets)
@ -1136,8 +1136,9 @@ func (h *FloatHistogram) ReduceResolution(targetSchema int32) *FloatHistogram {
panic(fmt.Errorf("cannot reduce resolution from schema %d to %d", h.Schema, targetSchema)) panic(fmt.Errorf("cannot reduce resolution from schema %d to %d", h.Schema, targetSchema))
} }
h.PositiveSpans, h.PositiveBuckets = reduceResolution(h.PositiveSpans, h.PositiveBuckets, h.Schema, targetSchema, false) h.PositiveSpans, h.PositiveBuckets = reduceResolution(h.PositiveSpans, h.PositiveBuckets, h.Schema, targetSchema, false, true)
h.NegativeSpans, h.NegativeBuckets = reduceResolution(h.NegativeSpans, h.NegativeBuckets, h.Schema, targetSchema, false) h.NegativeSpans, h.NegativeBuckets = reduceResolution(h.NegativeSpans, h.NegativeBuckets, h.Schema, targetSchema, false, true)
h.Schema = targetSchema h.Schema = targetSchema
return h return h
} }

View file

@ -1734,7 +1734,10 @@ func TestFloatHistogramCopyToSchema(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
inCopy := c.in.Copy()
require.Equal(t, c.expected, c.in.CopyToSchema(c.targetSchema)) require.Equal(t, c.expected, c.in.CopyToSchema(c.targetSchema))
// Check that the receiver histogram was not mutated:
require.Equal(t, inCopy, c.in)
}) })
} }
} }
@ -2489,5 +2492,7 @@ func TestFloatHistogramReduceResolution(t *testing.T) {
for _, tc := range tcs { for _, tc := range tcs {
target := tc.origin.ReduceResolution(tc.target.Schema) target := tc.origin.ReduceResolution(tc.target.Schema)
require.Equal(t, tc.target, target) require.Equal(t, tc.target, target)
// Check that receiver histogram was mutated:
require.Equal(t, tc.target, tc.origin)
} }
} }

View file

@ -605,7 +605,16 @@ var exponentialBounds = [][]float64{
// The target schema must be smaller than the original schema. // The target schema must be smaller than the original schema.
// Set deltaBuckets to true if the provided buckets are // Set deltaBuckets to true if the provided buckets are
// deltas. Set it to false if the buckets contain absolute counts. // deltas. Set it to false if the buckets contain absolute counts.
func reduceResolution[IBC InternalBucketCount](originSpans []Span, originBuckets []IBC, originSchema, targetSchema int32, deltaBuckets bool) ([]Span, []IBC) { // Set inplace to true to reuse input slices and avoid allocations (otherwise
// new slices will be allocated for result).
func reduceResolution[IBC InternalBucketCount](
originSpans []Span,
originBuckets []IBC,
originSchema,
targetSchema int32,
deltaBuckets bool,
inplace bool,
) ([]Span, []IBC) {
var ( var (
targetSpans []Span // The spans in the target schema. targetSpans []Span // The spans in the target schema.
targetBuckets []IBC // The bucket counts in the target schema. targetBuckets []IBC // The bucket counts in the target schema.
@ -617,6 +626,13 @@ func reduceResolution[IBC InternalBucketCount](originSpans []Span, originBuckets
lastTargetBucketCount IBC lastTargetBucketCount IBC
) )
if inplace {
// Slice reuse is safe because when reducing the resolution,
// target slices don't grow faster than origin slices are being read.
targetSpans = originSpans[:0]
targetBuckets = originBuckets[:0]
}
for _, span := range originSpans { for _, span := range originSpans {
// Determine the index of the first bucket in this span. // Determine the index of the first bucket in this span.
bucketIdx += span.Offset bucketIdx += span.Offset

View file

@ -15,6 +15,7 @@ package histogram
import ( import (
"math" "math"
"slices"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -140,9 +141,22 @@ func TestReduceResolutionHistogram(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
spans, buckets := reduceResolution(tc.spans, tc.buckets, tc.schema, tc.targetSchema, true) spansCopy, bucketsCopy := slices.Clone(tc.spans), slices.Clone(tc.buckets)
spans, buckets := reduceResolution(tc.spans, tc.buckets, tc.schema, tc.targetSchema, true, false)
require.Equal(t, tc.expectedSpans, spans) require.Equal(t, tc.expectedSpans, spans)
require.Equal(t, tc.expectedBuckets, buckets) require.Equal(t, tc.expectedBuckets, buckets)
// Verify inputs were not mutated:
require.Equal(t, spansCopy, tc.spans)
require.Equal(t, bucketsCopy, tc.buckets)
// Output slices reuse input slices:
const inplace = true
spans, buckets = reduceResolution(tc.spans, tc.buckets, tc.schema, tc.targetSchema, true, inplace)
require.Equal(t, tc.expectedSpans, spans)
require.Equal(t, tc.expectedBuckets, buckets)
// Verify inputs were mutated which is now expected:
require.Equal(t, spans, tc.spans[:len(spans)])
require.Equal(t, buckets, tc.buckets[:len(buckets)])
} }
} }
@ -175,8 +189,21 @@ func TestReduceResolutionFloatHistogram(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
spans, buckets := reduceResolution(tc.spans, tc.buckets, tc.schema, tc.targetSchema, false) spansCopy, bucketsCopy := slices.Clone(tc.spans), slices.Clone(tc.buckets)
spans, buckets := reduceResolution(tc.spans, tc.buckets, tc.schema, tc.targetSchema, false, false)
require.Equal(t, tc.expectedSpans, spans) require.Equal(t, tc.expectedSpans, spans)
require.Equal(t, tc.expectedBuckets, buckets) require.Equal(t, tc.expectedBuckets, buckets)
// Verify inputs were not mutated:
require.Equal(t, spansCopy, tc.spans)
require.Equal(t, bucketsCopy, tc.buckets)
// Output slices reuse input slices:
const inplace = true
spans, buckets = reduceResolution(tc.spans, tc.buckets, tc.schema, tc.targetSchema, false, inplace)
require.Equal(t, tc.expectedSpans, spans)
require.Equal(t, tc.expectedBuckets, buckets)
// Verify inputs were mutated which is now expected:
require.Equal(t, spans, tc.spans[:len(spans)])
require.Equal(t, buckets, tc.buckets[:len(buckets)])
} }
} }

View file

@ -502,10 +502,10 @@ func (h *Histogram) ReduceResolution(targetSchema int32) *Histogram {
} }
h.PositiveSpans, h.PositiveBuckets = reduceResolution( h.PositiveSpans, h.PositiveBuckets = reduceResolution(
h.PositiveSpans, h.PositiveBuckets, h.Schema, targetSchema, true, h.PositiveSpans, h.PositiveBuckets, h.Schema, targetSchema, true, true,
) )
h.NegativeSpans, h.NegativeBuckets = reduceResolution( h.NegativeSpans, h.NegativeBuckets = reduceResolution(
h.NegativeSpans, h.NegativeBuckets, h.Schema, targetSchema, true, h.NegativeSpans, h.NegativeBuckets, h.Schema, targetSchema, true, true,
) )
h.Schema = targetSchema h.Schema = targetSchema
return h return h

View file

@ -1008,5 +1008,7 @@ func TestHistogramReduceResolution(t *testing.T) {
for _, tc := range tcs { for _, tc := range tcs {
target := tc.origin.ReduceResolution(tc.target.Schema) target := tc.origin.ReduceResolution(tc.target.Schema)
require.Equal(t, tc.target, target) require.Equal(t, tc.target, target)
// Check that receiver histogram was mutated:
require.Equal(t, tc.target, tc.origin)
} }
} }