@@ -42,6 +42,7 @@ import (
4242 "github.com/thanos-io/thanos/pkg/runutil"
4343 "github.com/thanos-io/thanos/pkg/shipper"
4444 storecache "github.com/thanos-io/thanos/pkg/store/cache"
45+ "github.com/thanos-io/thanos/pkg/store/storepb"
4546 "github.com/weaveworks/common/httpgrpc"
4647 "github.com/weaveworks/common/middleware"
4748 "github.com/weaveworks/common/user"
@@ -3941,6 +3942,119 @@ func BenchmarkIngester_QueryStream_Chunks(b *testing.B) {
39413942 }
39423943}
39433944
3945+ func BenchmarkIngester_QueryStreamChunks_MatcherOptimization (b * testing.B ) {
3946+ tests := map [string ]struct {
3947+ matchers []* labels.Matcher
3948+ description string
3949+ }{
3950+ "metric name with regex matchers" : {
3951+ matchers : []* labels.Matcher {
3952+ labels .MustNewMatcher (labels .MatchEqual , model .MetricNameLabel , "test_metric" ),
3953+ labels .MustNewMatcher (labels .MatchRegexp , "region" , ".+" ),
3954+ labels .MustNewMatcher (labels .MatchRegexp , "job" , ".+" ),
3955+ },
3956+ description : "Metric name with .+ regex matchers" ,
3957+ },
3958+ "metric name with not equal empty" : {
3959+ matchers : []* labels.Matcher {
3960+ labels .MustNewMatcher (labels .MatchEqual , model .MetricNameLabel , "test_metric" ),
3961+ labels .MustNewMatcher (labels .MatchNotEqual , "env" , "" ),
3962+ labels .MustNewMatcher (labels .MatchNotEqual , "pod" , "" ),
3963+ },
3964+ description : "Metric name with != \" \" matchers" ,
3965+ },
3966+ "complex matchers" : {
3967+ matchers : []* labels.Matcher {
3968+ labels .MustNewMatcher (labels .MatchEqual , model .MetricNameLabel , "test_metric" ),
3969+ labels .MustNewMatcher (labels .MatchRegexp , "region" , ".+" ),
3970+ labels .MustNewMatcher (labels .MatchRegexp , "job" , ".+" ),
3971+ labels .MustNewMatcher (labels .MatchRegexp , "env" , ".+" ),
3972+ labels .MustNewMatcher (labels .MatchRegexp , "pod" , ".+" ),
3973+ },
3974+ description : "Complex matchers with .+ regex" ,
3975+ },
3976+ }
3977+
3978+ for testName , testData := range tests {
3979+ b .Run (testName + "_optimization_disabled" , func (b * testing.B ) {
3980+ benchmarkQueryStreamChunksWithMatcherOptimization (b , false , testData .matchers , testData .description + " without optimization" )
3981+ })
3982+ b .Run (testName + "_optimization_enabled" , func (b * testing.B ) {
3983+ benchmarkQueryStreamChunksWithMatcherOptimization (b , true , testData .matchers , testData .description + " with optimization" )
3984+ })
3985+ }
3986+ }
3987+
3988+ func benchmarkQueryStreamChunksWithMatcherOptimization (b * testing.B , enableMatcherOptimization bool , matchers []* labels.Matcher , description string ) {
3989+ cfg := defaultIngesterTestConfig (b )
3990+ cfg .EnableMatcherOptimization = enableMatcherOptimization
3991+
3992+ i , err := prepareIngesterWithBlocksStorage (b , cfg , prometheus .NewRegistry ())
3993+ require .NoError (b , err )
3994+ require .NoError (b , services .StartAndAwaitRunning (context .Background (), i ))
3995+ defer services .StopAndAwaitTerminated (context .Background (), i ) //nolint:errcheck
3996+
3997+ // Wait until it's ACTIVE
3998+ test .Poll (b , 1 * time .Second , ring .ACTIVE , func () any {
3999+ return i .lifecycler .GetState ()
4000+ })
4001+
4002+ ctx := user .InjectOrgID (context .Background (), userID )
4003+
4004+ for s := 0 ; s < 1000 ; s ++ {
4005+ lbls := labels .FromStrings (
4006+ labels .MetricName , "test_metric" ,
4007+ "region" , fmt .Sprintf ("region-%d" , s % 10 ),
4008+ "job" , fmt .Sprintf ("job-%d" , s % 20 ),
4009+ "env" , fmt .Sprintf ("env-%d" , s % 5 ),
4010+ "pod" , fmt .Sprintf ("pod-%d" , s % 1000 ),
4011+ )
4012+
4013+ samples := make ([]cortexpb.Sample , 0 , 5 )
4014+ for t := 0 ; t < 5 ; t ++ {
4015+ samples = append (samples , cortexpb.Sample {
4016+ Value : float64 (s + t ),
4017+ TimestampMs : int64 (s * 5 + t ),
4018+ })
4019+ }
4020+
4021+ // Create labels slice with same length as samples
4022+ labelsSlice := make ([]labels.Labels , len (samples ))
4023+ for j := range labelsSlice {
4024+ labelsSlice [j ] = lbls
4025+ }
4026+
4027+ req := cortexpb .ToWriteRequest (labelsSlice , samples , nil , nil , cortexpb .API )
4028+ _ , err = i .Push (ctx , req )
4029+ require .NoError (b , err )
4030+ }
4031+
4032+ db , err := i .getTSDB (userID )
4033+ require .NoError (b , err )
4034+ require .NotNil (b , db )
4035+
4036+ mockStream := & mockQueryStreamServer {ctx : ctx }
4037+ sm := (& storepb.ShardInfo {
4038+ TotalShards : 0 ,
4039+ }).Matcher (nil )
4040+
4041+ b .ReportAllocs ()
4042+ b .ResetTimer ()
4043+
4044+ for b .Loop () {
4045+ numSeries , numSamples , _ , numChunks , err := i .queryStreamChunks (
4046+ ctx , db , 0 , 5000 , matchers , sm , mockStream )
4047+
4048+ require .NoError (b , err )
4049+ require .Greater (b , numSeries , 0 )
4050+ require .Greater (b , numSamples , 0 )
4051+ require .Greater (b , numChunks , 0 )
4052+
4053+ // Reset the mock stream for next iteration
4054+ mockStream .series = mockStream .series [:0 ]
4055+ }
4056+ }
4057+
39444058func benchmarkQueryStream (b * testing.B , samplesCount , seriesCount int ) {
39454059 cfg := defaultIngesterTestConfig (b )
39464060
0 commit comments