mirror of
https://github.com/prometheus/prometheus.git
synced 2026-06-09 16:40:06 -04:00
test and benchmark updates
Signed-off-by: Owen Williams <owen.williams@grafana.com>
This commit is contained in:
parent
049827042a
commit
f3b20d7bda
4 changed files with 412 additions and 9 deletions
|
|
@ -217,3 +217,218 @@ func BenchmarkDecode_Samples(b *testing.B) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
histDataCases = testrecord.HistDataCases
|
||||
histCounts = testrecord.HistCounts
|
||||
)
|
||||
|
||||
/*
|
||||
go test ./tsdb/record/... \
|
||||
-run '^$' -bench '^BenchmarkEncode_Histograms' \
|
||||
-benchtime 5s -count 6 -cpu 2 -timeout 999m \
|
||||
| tee encode-hist.txt
|
||||
benchstat -col /version encode-hist.txt
|
||||
*/
|
||||
func BenchmarkEncode_Histograms(b *testing.B) {
|
||||
for _, ver := range versions {
|
||||
for _, compr := range compressions {
|
||||
for _, hcase := range histDataCases {
|
||||
for _, count := range histCounts {
|
||||
b.Run(fmt.Sprintf("version=%s/compr=%v/type=%s/n=%d", ver.name, compr, hcase.Name, count), func(b *testing.B) {
|
||||
var (
|
||||
samples = hcase.Gen(count, ver.enableST)
|
||||
enc = record.Encoder{EnableSTStorage: ver.enableST}
|
||||
buf []byte
|
||||
cBuf []byte
|
||||
)
|
||||
|
||||
cEnc, err := compression.NewEncoder()
|
||||
require.NoError(b, err)
|
||||
|
||||
// Warm up.
|
||||
if hcase.Name == "nhcb" {
|
||||
buf = enc.CustomBucketsHistogramSamples(samples, buf[:0])
|
||||
} else {
|
||||
buf, _ = enc.HistogramSamples(samples, buf[:0])
|
||||
}
|
||||
cBuf, _, err = cEnc.Encode(compr, buf, cBuf[:0])
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
if hcase.Name == "nhcb" {
|
||||
buf = enc.CustomBucketsHistogramSamples(samples, buf[:0])
|
||||
} else {
|
||||
buf, _ = enc.HistogramSamples(samples, buf[:0])
|
||||
}
|
||||
b.ReportMetric(float64(len(buf)), "B/rec")
|
||||
|
||||
cBuf, _, _ = cEnc.Encode(compr, buf, cBuf[:0])
|
||||
b.ReportMetric(float64(len(cBuf)), "B/compressed-rec")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
go test ./tsdb/record/... \
|
||||
-run '^$' -bench '^BenchmarkDecode_Histograms' \
|
||||
-benchtime 5s -count 6 -cpu 2 -timeout 999m \
|
||||
| tee decode-hist.txt
|
||||
benchstat -col /version decode-hist.txt
|
||||
*/
|
||||
func BenchmarkDecode_Histograms(b *testing.B) {
|
||||
for _, ver := range versions {
|
||||
for _, compr := range compressions {
|
||||
for _, hcase := range histDataCases {
|
||||
for _, count := range histCounts {
|
||||
b.Run(fmt.Sprintf("version=%s/compr=%v/type=%s/n=%d", ver.name, compr, hcase.Name, count), func(b *testing.B) {
|
||||
var (
|
||||
samples = hcase.Gen(count, ver.enableST)
|
||||
enc = record.Encoder{EnableSTStorage: ver.enableST}
|
||||
dec record.Decoder
|
||||
cDec = compression.NewDecoder()
|
||||
cBuf []byte
|
||||
samplesBuf []record.RefHistogramSample
|
||||
)
|
||||
|
||||
var buf []byte
|
||||
if hcase.Name == "nhcb" {
|
||||
buf = enc.CustomBucketsHistogramSamples(samples, nil)
|
||||
} else {
|
||||
buf, _ = enc.HistogramSamples(samples, nil)
|
||||
}
|
||||
|
||||
cEnc, err := compression.NewEncoder()
|
||||
require.NoError(b, err)
|
||||
buf, _, err = cEnc.Encode(compr, buf, nil)
|
||||
require.NoError(b, err)
|
||||
|
||||
// Warm up.
|
||||
cBuf, err = cDec.Decode(compr, buf, cBuf[:0])
|
||||
require.NoError(b, err)
|
||||
samplesBuf, err = dec.HistogramSamples(cBuf, samplesBuf[:0])
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
cBuf, _ = cDec.Decode(compr, buf, cBuf[:0])
|
||||
samplesBuf, _ = dec.HistogramSamples(cBuf, samplesBuf[:0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
go test ./tsdb/record/... \
|
||||
-run '^$' -bench '^BenchmarkEncode_FloatHistograms' \
|
||||
-benchtime 5s -count 6 -cpu 2 -timeout 999m \
|
||||
| tee encode-fhist.txt
|
||||
benchstat -col /version encode-fhist.txt
|
||||
*/
|
||||
func BenchmarkEncode_FloatHistograms(b *testing.B) {
|
||||
for _, ver := range versions {
|
||||
for _, compr := range compressions {
|
||||
for _, hcase := range histDataCases {
|
||||
for _, count := range histCounts {
|
||||
b.Run(fmt.Sprintf("version=%s/compr=%v/type=%s/n=%d", ver.name, compr, hcase.Name, count), func(b *testing.B) {
|
||||
var (
|
||||
samples = testrecord.GenFloatHistograms(hcase.Gen(count, ver.enableST))
|
||||
enc = record.Encoder{EnableSTStorage: ver.enableST}
|
||||
buf []byte
|
||||
cBuf []byte
|
||||
)
|
||||
|
||||
cEnc, err := compression.NewEncoder()
|
||||
require.NoError(b, err)
|
||||
|
||||
// Warm up.
|
||||
if hcase.Name == "nhcb" {
|
||||
buf = enc.CustomBucketsFloatHistogramSamples(samples, buf[:0])
|
||||
} else {
|
||||
buf, _ = enc.FloatHistogramSamples(samples, buf[:0])
|
||||
}
|
||||
cBuf, _, err = cEnc.Encode(compr, buf, cBuf[:0])
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
if hcase.Name == "nhcb" {
|
||||
buf = enc.CustomBucketsFloatHistogramSamples(samples, buf[:0])
|
||||
} else {
|
||||
buf, _ = enc.FloatHistogramSamples(samples, buf[:0])
|
||||
}
|
||||
b.ReportMetric(float64(len(buf)), "B/rec")
|
||||
|
||||
cBuf, _, _ = cEnc.Encode(compr, buf, cBuf[:0])
|
||||
b.ReportMetric(float64(len(cBuf)), "B/compressed-rec")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
go test ./tsdb/record/... \
|
||||
-run '^$' -bench '^BenchmarkDecode_FloatHistograms' \
|
||||
-benchtime 5s -count 6 -cpu 2 -timeout 999m \
|
||||
| tee decode-fhist.txt
|
||||
benchstat -col /version decode-fhist.txt
|
||||
*/
|
||||
func BenchmarkDecode_FloatHistograms(b *testing.B) {
|
||||
for _, ver := range versions {
|
||||
for _, compr := range compressions {
|
||||
for _, hcase := range histDataCases {
|
||||
for _, count := range histCounts {
|
||||
b.Run(fmt.Sprintf("version=%s/compr=%v/type=%s/n=%d", ver.name, compr, hcase.Name, count), func(b *testing.B) {
|
||||
var (
|
||||
samples = testrecord.GenFloatHistograms(hcase.Gen(count, ver.enableST))
|
||||
enc = record.Encoder{EnableSTStorage: ver.enableST}
|
||||
dec record.Decoder
|
||||
cDec = compression.NewDecoder()
|
||||
cBuf []byte
|
||||
samplesBuf []record.RefFloatHistogramSample
|
||||
)
|
||||
|
||||
var buf []byte
|
||||
if hcase.Name == "nhcb" {
|
||||
buf = enc.CustomBucketsFloatHistogramSamples(samples, nil)
|
||||
} else {
|
||||
buf, _ = enc.FloatHistogramSamples(samples, nil)
|
||||
}
|
||||
|
||||
cEnc, err := compression.NewEncoder()
|
||||
require.NoError(b, err)
|
||||
buf, _, err = cEnc.Encode(compr, buf, nil)
|
||||
require.NoError(b, err)
|
||||
|
||||
// Warm up.
|
||||
cBuf, err = cDec.Decode(compr, buf, cBuf[:0])
|
||||
require.NoError(b, err)
|
||||
samplesBuf, err = dec.FloatHistogramSamples(cBuf, samplesBuf[:0])
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
cBuf, _ = cDec.Decode(compr, buf, cBuf[:0])
|
||||
samplesBuf, _ = dec.FloatHistogramSamples(cBuf, samplesBuf[:0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1119,12 +1119,17 @@ func (*Encoder) histogramSamplesV2(histograms []RefHistogramSample, b []byte) ([
|
|||
|
||||
var customBucketHistograms []RefHistogramSample
|
||||
|
||||
// First sample: full varint values, no deltas, no ST marker.
|
||||
first := histograms[0]
|
||||
buf.PutVarint64(int64(first.Ref))
|
||||
buf.PutVarint64(first.T)
|
||||
buf.PutVarint64(first.ST)
|
||||
EncodeHistogram(&buf, first.H)
|
||||
|
||||
// First sample: full varint values, no deltas, no ST marker.
|
||||
if first.H.UsesCustomBuckets() {
|
||||
customBucketHistograms = append(customBucketHistograms, first)
|
||||
} else {
|
||||
buf.PutVarint64(int64(first.Ref))
|
||||
buf.PutVarint64(first.T)
|
||||
buf.PutVarint64(first.ST)
|
||||
EncodeHistogram(&buf, first.H)
|
||||
}
|
||||
|
||||
// Subsequent samples: ref delta to prev, T delta to first, ST marker.
|
||||
for i := 1; i < len(histograms); i++ {
|
||||
|
|
@ -1321,10 +1326,15 @@ func (*Encoder) floatHistogramSamplesV2(histograms []RefFloatHistogramSample, b
|
|||
var customBucketsFloatHistograms []RefFloatHistogramSample
|
||||
|
||||
first := histograms[0]
|
||||
buf.PutVarint64(int64(first.Ref))
|
||||
buf.PutVarint64(first.T)
|
||||
buf.PutVarint64(first.ST)
|
||||
EncodeFloatHistogram(&buf, first.FH)
|
||||
|
||||
if first.FH.UsesCustomBuckets() {
|
||||
customBucketsFloatHistograms = append(customBucketsFloatHistograms, first)
|
||||
} else {
|
||||
buf.PutVarint64(int64(first.Ref))
|
||||
buf.PutVarint64(first.T)
|
||||
buf.PutVarint64(first.ST)
|
||||
EncodeFloatHistogram(&buf, first.FH)
|
||||
}
|
||||
|
||||
for i := 1; i < len(histograms); i++ {
|
||||
h := histograms[i]
|
||||
|
|
|
|||
|
|
@ -485,6 +485,94 @@ func TestRecord_EncodeDecode(t *testing.T) {
|
|||
require.Equal(t, gaugeFloatHistsV2, decFloatHistsV2)
|
||||
})
|
||||
|
||||
for _, enableSTStorage := range []bool{false, true} {
|
||||
t.Run(fmt.Sprintf("int-histogram empty slice stStorage=%v", enableSTStorage), func(t *testing.T) {
|
||||
enc := Encoder{EnableSTStorage: enableSTStorage}
|
||||
histBuf, customBuckets := enc.HistogramSamples(nil, nil)
|
||||
require.Nil(t, customBuckets)
|
||||
|
||||
decoded, err := dec.HistogramSamples(histBuf, nil)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, decoded)
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("float-histogram empty slice stStorage=%v", enableSTStorage), func(t *testing.T) {
|
||||
enc := Encoder{EnableSTStorage: enableSTStorage}
|
||||
floatBuf, customBucketsFloat := enc.FloatHistogramSamples(nil, nil)
|
||||
require.Nil(t, customBucketsFloat)
|
||||
|
||||
decoded, err := dec.FloatHistogramSamples(floatBuf, nil)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, decoded)
|
||||
})
|
||||
}
|
||||
|
||||
// When all histograms are custom-bucket, HistogramSamples must return an
|
||||
// empty buffer (buf.Reset path) and pass every sample through as custom.
|
||||
t.Run("V2 int-histogram all custom bucket", func(t *testing.T) {
|
||||
allCustom := []RefHistogramSample{
|
||||
{Ref: 56, T: 1234, ST: 1000, H: histograms[2].H},
|
||||
{Ref: 67, T: 5678, ST: 1000, H: histograms[2].H},
|
||||
}
|
||||
histBuf, customBuckets := enc.HistogramSamples(allCustom, nil)
|
||||
require.Empty(t, histBuf, "regular histogram buffer must be empty when all samples are custom bucket")
|
||||
require.Equal(t, allCustom, customBuckets)
|
||||
|
||||
customBuf := enc.CustomBucketsHistogramSamples(customBuckets, nil)
|
||||
decoded, err := dec.HistogramSamples(customBuf, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, allCustom, decoded)
|
||||
})
|
||||
|
||||
t.Run("V2 float-histogram all custom bucket", func(t *testing.T) {
|
||||
allCustomFloat := []RefFloatHistogramSample{
|
||||
{Ref: 56, T: 1234, ST: 1000, FH: histograms[2].H.ToFloat(nil)},
|
||||
{Ref: 67, T: 5678, ST: 1000, FH: histograms[2].H.ToFloat(nil)},
|
||||
}
|
||||
floatBuf, customBucketsFloat := enc.FloatHistogramSamples(allCustomFloat, nil)
|
||||
require.Empty(t, floatBuf, "regular float histogram buffer must be empty when all samples are custom bucket")
|
||||
require.Equal(t, allCustomFloat, customBucketsFloat)
|
||||
|
||||
customFloatBuf := enc.CustomBucketsFloatHistogramSamples(customBucketsFloat, nil)
|
||||
decoded, err := dec.FloatHistogramSamples(customFloatBuf, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, allCustomFloat, decoded)
|
||||
})
|
||||
|
||||
// When all histograms are custom-bucket, V1 HistogramSamples must return an
|
||||
// empty buffer (buf.Reset path) and pass every sample through as custom.
|
||||
t.Run("V1 int-histogram all custom bucket", func(t *testing.T) {
|
||||
encV1 := Encoder{}
|
||||
allCustom := []RefHistogramSample{
|
||||
{Ref: 56, T: 1234, H: histograms[2].H},
|
||||
{Ref: 67, T: 5678, H: histograms[2].H},
|
||||
}
|
||||
histBuf, customBuckets := encV1.HistogramSamples(allCustom, nil)
|
||||
require.Empty(t, histBuf, "regular histogram buffer must be empty when all samples are custom bucket")
|
||||
require.Equal(t, allCustom, customBuckets)
|
||||
|
||||
customBuf := encV1.CustomBucketsHistogramSamples(customBuckets, nil)
|
||||
decoded, err := dec.HistogramSamples(customBuf, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, allCustom, decoded)
|
||||
})
|
||||
|
||||
t.Run("V1 float-histogram all custom bucket", func(t *testing.T) {
|
||||
encV1 := Encoder{}
|
||||
allCustomFloat := []RefFloatHistogramSample{
|
||||
{Ref: 56, T: 1234, FH: histograms[2].H.ToFloat(nil)},
|
||||
{Ref: 67, T: 5678, FH: histograms[2].H.ToFloat(nil)},
|
||||
}
|
||||
floatBuf, customBucketsFloat := encV1.FloatHistogramSamples(allCustomFloat, nil)
|
||||
require.Empty(t, floatBuf, "regular float histogram buffer must be empty when all samples are custom bucket")
|
||||
require.Equal(t, allCustomFloat, customBucketsFloat)
|
||||
|
||||
customFloatBuf := encV1.CustomBucketsFloatHistogramSamples(customBucketsFloat, nil)
|
||||
decoded, err := dec.FloatHistogramSamples(customFloatBuf, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, allCustomFloat, decoded)
|
||||
})
|
||||
|
||||
// Backward compat: V1-encoded histograms decode with ST=0.
|
||||
t.Run("V1 backward compat int-histogram ST=0", func(t *testing.T) {
|
||||
encV1 := Encoder{}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/tsdb/chunks"
|
||||
"github.com/prometheus/prometheus/tsdb/record"
|
||||
)
|
||||
|
|
@ -81,6 +82,95 @@ func GenTestRefSamplesCase(t testing.TB, c RefSamplesCase) []record.RefSample {
|
|||
return ret
|
||||
}
|
||||
|
||||
// GenExpHistograms generates n standard exponential histograms (schema=1)
|
||||
// with incrementing refs, same timestamp, and realistic bucket distributions.
|
||||
// If withST is true, all samples get a constant ST (simulating sameST marker path).
|
||||
func GenExpHistograms(n int, withST bool) []record.RefHistogramSample {
|
||||
out := make([]record.RefHistogramSample, n)
|
||||
for i := range out {
|
||||
out[i] = record.RefHistogramSample{
|
||||
Ref: chunks.HeadSeriesRef(i),
|
||||
T: 1709000000 + int64(i)*15,
|
||||
H: &histogram.Histogram{
|
||||
Count: uint64(10 + i%100),
|
||||
ZeroCount: uint64(1 + i%5),
|
||||
ZeroThreshold: 0.001,
|
||||
Sum: float64(100+i) * 1.5,
|
||||
Schema: 1,
|
||||
PositiveSpans: []histogram.Span{
|
||||
{Offset: 0, Length: 4},
|
||||
{Offset: 2, Length: 3},
|
||||
},
|
||||
PositiveBuckets: []int64{1, 2, -1, 0, 3, -2, 1},
|
||||
NegativeSpans: []histogram.Span{
|
||||
{Offset: 0, Length: 2},
|
||||
{Offset: 1, Length: 2},
|
||||
},
|
||||
NegativeBuckets: []int64{1, 1, -1, 0},
|
||||
},
|
||||
}
|
||||
if withST {
|
||||
out[i].ST = 1709000000
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// GenCustomBucketHistograms generates n custom-bucket (NHCB) histograms (schema=-53)
|
||||
// with incrementing refs. If withST is true, all samples get a constant ST.
|
||||
func GenCustomBucketHistograms(n int, withST bool) []record.RefHistogramSample {
|
||||
out := make([]record.RefHistogramSample, n)
|
||||
for i := range out {
|
||||
out[i] = record.RefHistogramSample{
|
||||
Ref: chunks.HeadSeriesRef(i),
|
||||
T: 1709000000 + int64(i)*15,
|
||||
H: &histogram.Histogram{
|
||||
Count: uint64(10 + i%100),
|
||||
Sum: float64(100+i) * 1.5,
|
||||
Schema: histogram.CustomBucketsSchema,
|
||||
PositiveSpans: []histogram.Span{
|
||||
{Offset: 0, Length: 8},
|
||||
},
|
||||
PositiveBuckets: []int64{5, -2, 3, -1, 4, 0, -3, 2},
|
||||
CustomValues: []float64{0.001, 0.01, 0.1, 1, 10, 100, 1000},
|
||||
},
|
||||
}
|
||||
if withST {
|
||||
out[i].ST = 1709000000
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// GenFloatHistograms converts int histograms to float histograms, preserving ST.
|
||||
func GenFloatHistograms(src []record.RefHistogramSample) []record.RefFloatHistogramSample {
|
||||
out := make([]record.RefFloatHistogramSample, len(src))
|
||||
for i, h := range src {
|
||||
out[i] = record.RefFloatHistogramSample{
|
||||
Ref: h.Ref,
|
||||
ST: h.ST,
|
||||
T: h.T,
|
||||
FH: h.H.ToFloat(nil),
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// HistDataCase pairs a name with a histogram generator for benchmark tables.
|
||||
type HistDataCase struct {
|
||||
Name string
|
||||
Gen func(n int, withST bool) []record.RefHistogramSample
|
||||
}
|
||||
|
||||
// HistDataCases is the standard set of histogram data cases for benchmarks.
|
||||
var HistDataCases = []HistDataCase{
|
||||
{"exp", GenExpHistograms},
|
||||
{"nhcb", GenCustomBucketHistograms},
|
||||
}
|
||||
|
||||
// HistCounts is the standard set of histogram counts for benchmarks.
|
||||
var HistCounts = []int{10, 100, 1000}
|
||||
|
||||
func highVarianceInt(i int) int64 {
|
||||
if i%2 == 0 {
|
||||
return math.MinInt32
|
||||
|
|
|
|||
Loading…
Reference in a new issue