| 
									
										
										
										
											2016-08-13 06:11:52 +08:00
										 |  |  | // Copyright 2016 The Prometheus Authors
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 08:52:59 +08:00
										 |  |  | package rules | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-06-17 15:54:25 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-08-12 08:52:59 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-08-12 08:52:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-12 00:17:59 +08:00
										 |  |  | 	"github.com/go-kit/log" | 
					
						
							| 
									
										
										
										
											2022-10-07 22:58:17 +08:00
										 |  |  | 	"github.com/prometheus/common/model" | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2020-10-22 17:00:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 22:23:17 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/model/labels" | 
					
						
							| 
									
										
										
										
											2022-10-07 22:58:17 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/model/relabel" | 
					
						
							| 
									
										
										
										
											2021-11-08 22:23:17 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/model/timestamp" | 
					
						
							| 
									
										
										
										
											2022-10-07 22:58:17 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/notifier" | 
					
						
							| 
									
										
										
										
											2016-08-12 08:52:59 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/promql" | 
					
						
							| 
									
										
										
										
											2020-02-04 02:23:07 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/promql/parser" | 
					
						
							| 
									
										
										
										
											2022-03-29 08:16:46 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/storage" | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/util/teststorage" | 
					
						
							| 
									
										
										
										
											2016-08-12 08:52:59 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | var testEngine = promql.NewEngine(promql.EngineOpts{ | 
					
						
							|  |  |  | 	Logger:                   nil, | 
					
						
							|  |  |  | 	Reg:                      nil, | 
					
						
							|  |  |  | 	MaxSamples:               10000, | 
					
						
							|  |  |  | 	Timeout:                  100 * time.Second, | 
					
						
							|  |  |  | 	NoStepSubqueryIntervalFn: func(int64) int64 { return 60 * 1000 }, | 
					
						
							|  |  |  | 	EnableAtModifier:         true, | 
					
						
							|  |  |  | 	EnableNegativeOffset:     true, | 
					
						
							|  |  |  | 	EnablePerStepStats:       true, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 20:16:52 +08:00
										 |  |  | func TestAlertingRuleState(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name   string | 
					
						
							|  |  |  | 		active map[uint64]*Alert | 
					
						
							|  |  |  | 		want   AlertState | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "MaxStateFiring", | 
					
						
							|  |  |  | 			active: map[uint64]*Alert{ | 
					
						
							|  |  |  | 				0: {State: StatePending}, | 
					
						
							|  |  |  | 				1: {State: StateFiring}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: StateFiring, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "MaxStatePending", | 
					
						
							|  |  |  | 			active: map[uint64]*Alert{ | 
					
						
							|  |  |  | 				0: {State: StateInactive}, | 
					
						
							|  |  |  | 				1: {State: StatePending}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: StatePending, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "MaxStateInactive", | 
					
						
							|  |  |  | 			active: map[uint64]*Alert{ | 
					
						
							|  |  |  | 				0: {State: StateInactive}, | 
					
						
							|  |  |  | 				1: {State: StateInactive}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: StateInactive, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range tests { | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		rule := NewAlertingRule(test.name, nil, 0, 0, labels.EmptyLabels(), labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil) | 
					
						
							| 
									
										
										
										
											2020-06-29 20:16:52 +08:00
										 |  |  | 		rule.active = test.active | 
					
						
							|  |  |  | 		got := rule.State() | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 		require.Equal(t, test.want, got, "test case %d unexpected AlertState, want:%d got:%d", i, test.want, got) | 
					
						
							| 
									
										
										
										
											2020-06-29 20:16:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | func TestAlertingRuleLabelsUpdate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 		load 1m | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 			http_requests{job="app-server", instance="0"}	75 85 70 70 stale | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 02:23:07 +08:00
										 |  |  | 	expr, err := parser.ParseExpr(`http_requests < 100`) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		"HTTPRequestRateLow", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 		// Basing alerting rule labels off of a value that can change is a very bad idea.
 | 
					
						
							|  |  |  | 		// If an alert is going back and forth between two label values it will never fire.
 | 
					
						
							|  |  |  | 		// Instead, you should write two alerts with constant labels.
 | 
					
						
							|  |  |  | 		labels.FromStrings("severity", "{{ if lt $value 80.0 }}critical{{ else }}warning{{ end }}"), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil, | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	results := []promql.Vector{ | 
					
						
							| 
									
										
										
										
											2019-01-17 06:28:08 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 			promql.Sample{ | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateLow", | 
					
						
							|  |  |  | 					"alertstate", "pending", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 					"severity", "critical", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2019-01-17 06:28:08 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 			promql.Sample{ | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateLow", | 
					
						
							|  |  |  | 					"alertstate", "pending", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 					"severity", "warning", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2019-01-17 06:28:08 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 			promql.Sample{ | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateLow", | 
					
						
							|  |  |  | 					"alertstate", "pending", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 					"severity", "critical", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2019-01-17 06:28:08 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 			promql.Sample{ | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateLow", | 
					
						
							|  |  |  | 					"alertstate", "firing", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 					"severity", "critical", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	baseTime := time.Unix(0, 0) | 
					
						
							|  |  |  | 	for i, result := range results { | 
					
						
							|  |  |  | 		t.Logf("case %d", i) | 
					
						
							|  |  |  | 		evalTime := baseTime.Add(time.Duration(i) * time.Minute) | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 		result[0].T = timestamp.FromTime(evalTime) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
 | 
					
						
							|  |  |  | 		for _, smpl := range res { | 
					
						
							|  |  |  | 			smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 			if smplName == "ALERTS" { | 
					
						
							|  |  |  | 				filteredRes = append(filteredRes, smpl) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 		require.Equal(t, result, filteredRes) | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 	evalTime := baseTime.Add(time.Duration(len(results)) * time.Minute) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0) | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	require.Equal(t, 0, len(res)) | 
					
						
							| 
									
										
										
										
											2018-08-15 15:52:08 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestAlertingRuleExternalLabelsInTemplate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		load 1m | 
					
						
							|  |  |  | 			http_requests{job="app-server", instance="0"}	75 85 70 70 | 
					
						
							|  |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 02:23:07 +08:00
										 |  |  | 	expr, err := parser.ParseExpr(`http_requests < 100`) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ruleWithoutExternalLabels := NewAlertingRule( | 
					
						
							|  |  |  | 		"ExternalLabelDoesNotExist", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		labels.FromStrings("templated_label", "There are {{ len $externalLabels }} external Labels, of which foo is {{ $externalLabels.foo }}."), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		"", | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	ruleWithExternalLabels := NewAlertingRule( | 
					
						
							|  |  |  | 		"ExternalLabelExists", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		labels.FromStrings("templated_label", "There are {{ len $externalLabels }} external Labels, of which foo is {{ $externalLabels.foo }}."), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		labels.FromStrings("foo", "bar", "dings", "bums"), | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		"", | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	result := promql.Vector{ | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 		promql.Sample{ | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 			Metric: labels.FromStrings( | 
					
						
							|  |  |  | 				"__name__", "ALERTS", | 
					
						
							|  |  |  | 				"alertname", "ExternalLabelDoesNotExist", | 
					
						
							|  |  |  | 				"alertstate", "pending", | 
					
						
							|  |  |  | 				"instance", "0", | 
					
						
							|  |  |  | 				"job", "app-server", | 
					
						
							|  |  |  | 				"templated_label", "There are 0 external Labels, of which foo is .", | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 			F: 1, | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 		promql.Sample{ | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 			Metric: labels.FromStrings( | 
					
						
							|  |  |  | 				"__name__", "ALERTS", | 
					
						
							|  |  |  | 				"alertname", "ExternalLabelExists", | 
					
						
							|  |  |  | 				"alertstate", "pending", | 
					
						
							|  |  |  | 				"instance", "0", | 
					
						
							|  |  |  | 				"job", "app-server", | 
					
						
							|  |  |  | 				"templated_label", "There are 2 external Labels, of which foo is bar.", | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 			F: 1, | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	evalTime := time.Unix(0, 0) | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 	result[0].T = timestamp.FromTime(evalTime) | 
					
						
							|  |  |  | 	result[1].T = timestamp.FromTime(evalTime) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
 | 
					
						
							|  |  |  | 	res, err := ruleWithoutExternalLabels.Eval( | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0, | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 	for _, smpl := range res { | 
					
						
							|  |  |  | 		smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 		if smplName == "ALERTS" { | 
					
						
							|  |  |  | 			filteredRes = append(filteredRes, smpl) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res, err = ruleWithExternalLabels.Eval( | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0, | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 	for _, smpl := range res { | 
					
						
							|  |  |  | 		smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 		if smplName == "ALERTS" { | 
					
						
							|  |  |  | 			filteredRes = append(filteredRes, smpl) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.Equal(t, result, filteredRes) | 
					
						
							| 
									
										
										
										
											2019-04-20 08:19:06 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | func TestAlertingRuleExternalURLInTemplate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		load 1m | 
					
						
							|  |  |  | 			http_requests{job="app-server", instance="0"}	75 85 70 70 | 
					
						
							|  |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	expr, err := parser.ParseExpr(`http_requests < 100`) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ruleWithoutExternalURL := NewAlertingRule( | 
					
						
							|  |  |  | 		"ExternalURLDoesNotExist", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		labels.FromStrings("templated_label", "The external URL is {{ $externalURL }}."), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		"", | 
					
						
							|  |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	ruleWithExternalURL := NewAlertingRule( | 
					
						
							|  |  |  | 		"ExternalURLExists", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		labels.FromStrings("templated_label", "The external URL is {{ $externalURL }}."), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		"http://localhost:1234", | 
					
						
							|  |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	result := promql.Vector{ | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 		promql.Sample{ | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 			Metric: labels.FromStrings( | 
					
						
							|  |  |  | 				"__name__", "ALERTS", | 
					
						
							|  |  |  | 				"alertname", "ExternalURLDoesNotExist", | 
					
						
							|  |  |  | 				"alertstate", "pending", | 
					
						
							|  |  |  | 				"instance", "0", | 
					
						
							|  |  |  | 				"job", "app-server", | 
					
						
							|  |  |  | 				"templated_label", "The external URL is .", | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 			F: 1, | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 		promql.Sample{ | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 			Metric: labels.FromStrings( | 
					
						
							|  |  |  | 				"__name__", "ALERTS", | 
					
						
							|  |  |  | 				"alertname", "ExternalURLExists", | 
					
						
							|  |  |  | 				"alertstate", "pending", | 
					
						
							|  |  |  | 				"instance", "0", | 
					
						
							|  |  |  | 				"job", "app-server", | 
					
						
							|  |  |  | 				"templated_label", "The external URL is http://localhost:1234.", | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 			F: 1, | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	evalTime := time.Unix(0, 0) | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 	result[0].T = timestamp.FromTime(evalTime) | 
					
						
							|  |  |  | 	result[1].T = timestamp.FromTime(evalTime) | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
 | 
					
						
							|  |  |  | 	res, err := ruleWithoutExternalURL.Eval( | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0, | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	for _, smpl := range res { | 
					
						
							|  |  |  | 		smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 		if smplName == "ALERTS" { | 
					
						
							|  |  |  | 			filteredRes = append(filteredRes, smpl) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							|  |  |  | 			require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res, err = ruleWithExternalURL.Eval( | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0, | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	for _, smpl := range res { | 
					
						
							|  |  |  | 		smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 		if smplName == "ALERTS" { | 
					
						
							|  |  |  | 			filteredRes = append(filteredRes, smpl) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							|  |  |  | 			require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require.Equal(t, result, filteredRes) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | func TestAlertingRuleEmptyLabelFromTemplate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 		load 1m | 
					
						
							|  |  |  | 			http_requests{job="app-server", instance="0"}	75 85 70 70 | 
					
						
							|  |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 02:23:07 +08:00
										 |  |  | 	expr, err := parser.ParseExpr(`http_requests < 100`) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		"EmptyLabel", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 		labels.FromStrings("empty_label", ""), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		"", | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	result := promql.Vector{ | 
					
						
							| 
									
										
										
										
											2021-11-18 02:57:31 +08:00
										 |  |  | 		promql.Sample{ | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 			Metric: labels.FromStrings( | 
					
						
							|  |  |  | 				"__name__", "ALERTS", | 
					
						
							|  |  |  | 				"alertname", "EmptyLabel", | 
					
						
							|  |  |  | 				"alertstate", "pending", | 
					
						
							|  |  |  | 				"instance", "0", | 
					
						
							|  |  |  | 				"job", "app-server", | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 			F: 1, | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	evalTime := time.Unix(0, 0) | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 	result[0].T = timestamp.FromTime(evalTime) | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
 | 
					
						
							|  |  |  | 	res, err := rule.Eval( | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0, | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 	for _, smpl := range res { | 
					
						
							|  |  |  | 		smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 		if smplName == "ALERTS" { | 
					
						
							|  |  |  | 			filteredRes = append(filteredRes, smpl) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.Equal(t, result, filteredRes) | 
					
						
							| 
									
										
										
										
											2019-08-13 18:19:17 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | func TestAlertingRuleQueryInTemplate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | 		load 1m | 
					
						
							|  |  |  | 			http_requests{job="app-server", instance="0"}	70 85 70 70 | 
					
						
							|  |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	expr, err := parser.ParseExpr(`sum(http_requests) < 100`) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ruleWithQueryInTemplate := NewAlertingRule( | 
					
						
							|  |  |  | 		"ruleWithQueryInTemplate", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | 		labels.FromStrings("label", "value"), | 
					
						
							|  |  |  | 		labels.FromStrings("templated_label", `{{- with "sort(sum(http_requests) by (instance))" | query -}} | 
					
						
							|  |  |  | {{- range $i,$v := . -}} | 
					
						
							|  |  |  | instance: {{ $v.Labels.instance }}, value: {{ printf "%.0f" $v.Value }}; | 
					
						
							|  |  |  | {{- end -}} | 
					
						
							|  |  |  | {{- end -}} | 
					
						
							|  |  |  | `), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | 		"", | 
					
						
							|  |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	evalTime := time.Unix(0, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	startQueryCh := make(chan struct{}) | 
					
						
							|  |  |  | 	getDoneCh := make(chan struct{}) | 
					
						
							|  |  |  | 	slowQueryFunc := func(ctx context.Context, q string, ts time.Time) (promql.Vector, error) { | 
					
						
							|  |  |  | 		if q == "sort(sum(http_requests) by (instance))" { | 
					
						
							|  |  |  | 			// This is a minimum reproduction of issue 10703, expand template with query.
 | 
					
						
							|  |  |  | 			close(startQueryCh) | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case <-getDoneCh: | 
					
						
							|  |  |  | 			case <-time.After(time.Millisecond * 10): | 
					
						
							|  |  |  | 				// Assert no blocking when template expanding.
 | 
					
						
							|  |  |  | 				require.Fail(t, "unexpected blocking when template expanding.") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		return EngineQueryFunc(testEngine, storage)(ctx, q, ts) | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		<-startQueryCh | 
					
						
							|  |  |  | 		_ = ruleWithQueryInTemplate.Health() | 
					
						
							|  |  |  | 		_ = ruleWithQueryInTemplate.LastError() | 
					
						
							|  |  |  | 		_ = ruleWithQueryInTemplate.GetEvaluationDuration() | 
					
						
							|  |  |  | 		_ = ruleWithQueryInTemplate.GetEvaluationTimestamp() | 
					
						
							|  |  |  | 		close(getDoneCh) | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	_, err = ruleWithQueryInTemplate.Eval( | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		context.TODO(), evalTime, slowQueryFunc, nil, 0, | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkAlertingRuleAtomicField(b *testing.B) { | 
					
						
							|  |  |  | 	b.ReportAllocs() | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 	rule := NewAlertingRule("bench", nil, 0, 0, labels.EmptyLabels(), labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil) | 
					
						
							| 
									
										
										
										
											2022-07-19 18:58:37 +08:00
										 |  |  | 	done := make(chan struct{}) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 			rule.GetEvaluationTimestamp() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		close(done) | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	b.RunParallel(func(pb *testing.PB) { | 
					
						
							|  |  |  | 		for pb.Next() { | 
					
						
							|  |  |  | 			rule.SetEvaluationTimestamp(time.Now()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	<-done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | func TestAlertingRuleDuplicate(t *testing.T) { | 
					
						
							|  |  |  | 	storage := teststorage.New(t) | 
					
						
							|  |  |  | 	defer storage.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	opts := promql.EngineOpts{ | 
					
						
							| 
									
										
										
										
											2020-01-29 04:38:49 +08:00
										 |  |  | 		Logger:     nil, | 
					
						
							|  |  |  | 		Reg:        nil, | 
					
						
							|  |  |  | 		MaxSamples: 10, | 
					
						
							|  |  |  | 		Timeout:    10 * time.Second, | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	engine := promql.NewEngine(opts) | 
					
						
							|  |  |  | 	ctx, cancelCtx := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	defer cancelCtx() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	now := time.Now() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 02:23:07 +08:00
										 |  |  | 	expr, _ := parser.ParseExpr(`vector(0) or label_replace(vector(0),"test","x","","")`) | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		"foo", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | 		labels.FromStrings("test", "test"), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2021-05-31 11:35:41 +08:00
										 |  |  | 		"", | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-09-15 15:48:26 +08:00
										 |  |  | 	_, err := rule.Eval(ctx, now, EngineQueryFunc(engine, storage), nil, 0) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	require.Error(t, err) | 
					
						
							|  |  |  | 	require.EqualError(t, err, "vector contains metrics with the same labelset after applying alert labels") | 
					
						
							| 
									
										
										
										
											2019-12-18 20:29:35 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-09-15 15:48:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestAlertingRuleLimit(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 		load 1m | 
					
						
							|  |  |  | 			metric{label="1"} 1 | 
					
						
							|  |  |  | 			metric{label="2"} 1 | 
					
						
							|  |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2021-09-15 15:48:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 	tests := []struct { | 
					
						
							| 
									
										
										
										
											2021-09-15 15:48:26 +08:00
										 |  |  | 		limit int | 
					
						
							|  |  |  | 		err   string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			limit: 0, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 			limit: -1, | 
					
						
							| 
									
										
										
										
											2021-09-15 15:48:26 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 			limit: 2, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			limit: 1, | 
					
						
							|  |  |  | 			err:   "exceeded limit of 1 with 2 alerts", | 
					
						
							| 
									
										
										
										
											2021-09-15 15:48:26 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 	expr, _ := parser.ParseExpr(`metric > 0`) | 
					
						
							|  |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		"foo", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 		labels.FromStrings("test", "test"), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 		"", | 
					
						
							|  |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	evalTime := time.Unix(0, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		switch _, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, test.limit); { | 
					
						
							| 
									
										
											  
											
												style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
  condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
  used. In this case, using `switch` would require tagging the `for`
  loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2023-04-12 22:14:31 +08:00
										 |  |  | 		case err != nil: | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 			require.EqualError(t, err, test.err) | 
					
						
							| 
									
										
											  
											
												style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
  condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
  used. In this case, using `switch` would require tagging the `for`
  loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2023-04-12 22:14:31 +08:00
										 |  |  | 		case test.err != "": | 
					
						
							| 
									
										
										
										
											2021-10-22 05:14:17 +08:00
										 |  |  | 			t.Errorf("Expected errror %s, got none", test.err) | 
					
						
							| 
									
										
										
										
											2021-09-15 15:48:26 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-29 08:16:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestQueryForStateSeries(t *testing.T) { | 
					
						
							|  |  |  | 	testError := errors.New("test error") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type testInput struct { | 
					
						
							|  |  |  | 		selectMockFunction func(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet | 
					
						
							|  |  |  | 		expectedSeries     storage.Series | 
					
						
							|  |  |  | 		expectedError      error | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tests := []testInput{ | 
					
						
							|  |  |  | 		// Test for empty series.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			selectMockFunction: func(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet { | 
					
						
							|  |  |  | 				return storage.EmptySeriesSet() | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedSeries: nil, | 
					
						
							|  |  |  | 			expectedError:  nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// Test for error series.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			selectMockFunction: func(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet { | 
					
						
							|  |  |  | 				return storage.ErrSeriesSet(testError) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedSeries: nil, | 
					
						
							|  |  |  | 			expectedError:  testError, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// Test for mock series.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			selectMockFunction: func(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet { | 
					
						
							|  |  |  | 				return storage.TestSeriesSet(storage.MockSeries( | 
					
						
							|  |  |  | 					[]int64{1, 2, 3}, | 
					
						
							|  |  |  | 					[]float64{1, 2, 3}, | 
					
						
							|  |  |  | 					[]string{"__name__", "ALERTS_FOR_STATE", "alertname", "TestRule", "severity", "critical"}, | 
					
						
							|  |  |  | 				)) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedSeries: storage.MockSeries( | 
					
						
							|  |  |  | 				[]int64{1, 2, 3}, | 
					
						
							|  |  |  | 				[]float64{1, 2, 3}, | 
					
						
							|  |  |  | 				[]string{"__name__", "ALERTS_FOR_STATE", "alertname", "TestRule", "severity", "critical"}, | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			expectedError: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testFunc := func(tst testInput) { | 
					
						
							|  |  |  | 		querier := &storage.MockQuerier{ | 
					
						
							|  |  |  | 			SelectMockFunction: tst.selectMockFunction, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rule := NewAlertingRule( | 
					
						
							|  |  |  | 			"TestRule", | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 			time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 			0, | 
					
						
							| 
									
										
										
										
											2022-03-29 08:16:46 +08:00
										 |  |  | 			labels.FromStrings("severity", "critical"), | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 			labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil, | 
					
						
							| 
									
										
										
										
											2022-03-29 08:16:46 +08:00
										 |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		alert := &Alert{ | 
					
						
							|  |  |  | 			State:       0, | 
					
						
							| 
									
										
										
										
											2022-07-22 00:44:35 +08:00
										 |  |  | 			Labels:      labels.EmptyLabels(), | 
					
						
							|  |  |  | 			Annotations: labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2022-03-29 08:16:46 +08:00
										 |  |  | 			Value:       0, | 
					
						
							|  |  |  | 			ActiveAt:    time.Time{}, | 
					
						
							|  |  |  | 			FiredAt:     time.Time{}, | 
					
						
							|  |  |  | 			ResolvedAt:  time.Time{}, | 
					
						
							|  |  |  | 			LastSentAt:  time.Time{}, | 
					
						
							|  |  |  | 			ValidUntil:  time.Time{}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-12 18:37:38 +08:00
										 |  |  | 		series, err := rule.QueryforStateSeries(context.Background(), alert, querier) | 
					
						
							| 
									
										
										
										
											2022-03-29 08:16:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		require.Equal(t, tst.expectedSeries, series) | 
					
						
							|  |  |  | 		require.Equal(t, tst.expectedError, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tst := range tests { | 
					
						
							|  |  |  | 		testFunc(tst) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-10-07 22:58:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestSendAlertsDontAffectActiveAlerts tests a fix for https://github.com/prometheus/prometheus/issues/11424.
 | 
					
						
							|  |  |  | func TestSendAlertsDontAffectActiveAlerts(t *testing.T) { | 
					
						
							|  |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		"TestRule", | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 19:21:38 +08:00
										 |  |  | 		0, | 
					
						
							| 
									
										
										
										
											2022-10-07 22:58:17 +08:00
										 |  |  | 		labels.FromStrings("severity", "critical"), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set an active alert.
 | 
					
						
							|  |  |  | 	lbls := labels.FromStrings("a1", "1") | 
					
						
							|  |  |  | 	h := lbls.Hash() | 
					
						
							|  |  |  | 	al := &Alert{State: StateFiring, Labels: lbls, ActiveAt: time.Now()} | 
					
						
							|  |  |  | 	rule.active[h] = al | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	expr, err := parser.ParseExpr("foo") | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	rule.vector = expr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The relabel rule reproduced the bug here.
 | 
					
						
							|  |  |  | 	opts := notifier.Options{ | 
					
						
							|  |  |  | 		QueueCapacity: 1, | 
					
						
							|  |  |  | 		RelabelConfigs: []*relabel.Config{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				SourceLabels: model.LabelNames{"a1"}, | 
					
						
							|  |  |  | 				Regex:        relabel.MustNewRegexp("(.+)"), | 
					
						
							|  |  |  | 				TargetLabel:  "a1", | 
					
						
							|  |  |  | 				Replacement:  "bug", | 
					
						
							|  |  |  | 				Action:       "replace", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	nm := notifier.NewManager(&opts, log.NewNopLogger()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	f := SendAlerts(nm, "") | 
					
						
							|  |  |  | 	notifyFunc := func(ctx context.Context, expr string, alerts ...*Alert) { | 
					
						
							|  |  |  | 		require.Len(t, alerts, 1) | 
					
						
							|  |  |  | 		require.Equal(t, al, alerts[0]) | 
					
						
							|  |  |  | 		f(ctx, expr, alerts...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rule.sendAlerts(context.Background(), time.Now(), 0, 0, notifyFunc) | 
					
						
							|  |  |  | 	nm.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The relabel rule changes a1=1 to a1=bug.
 | 
					
						
							|  |  |  | 	// But the labels with the AlertingRule should not be changed.
 | 
					
						
							|  |  |  | 	require.Equal(t, labels.FromStrings("a1", "1"), rule.active[h].Labels) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-01-09 16:14:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | func TestKeepFiringFor(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 		load 1m | 
					
						
							|  |  |  | 			http_requests{job="app-server", instance="0"}	75 85 70 70 10x5 | 
					
						
							|  |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	expr, err := parser.ParseExpr(`http_requests > 50`) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		"HTTPRequestRateHigh", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	results := []promql.Vector{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			promql.Sample{ | 
					
						
							|  |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateHigh", | 
					
						
							|  |  |  | 					"alertstate", "pending", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			promql.Sample{ | 
					
						
							|  |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateHigh", | 
					
						
							|  |  |  | 					"alertstate", "firing", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			promql.Sample{ | 
					
						
							|  |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateHigh", | 
					
						
							|  |  |  | 					"alertstate", "firing", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			promql.Sample{ | 
					
						
							|  |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateHigh", | 
					
						
							|  |  |  | 					"alertstate", "firing", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// From now on the alert should keep firing.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			promql.Sample{ | 
					
						
							|  |  |  | 				Metric: labels.FromStrings( | 
					
						
							|  |  |  | 					"__name__", "ALERTS", | 
					
						
							|  |  |  | 					"alertname", "HTTPRequestRateHigh", | 
					
						
							|  |  |  | 					"alertstate", "firing", | 
					
						
							|  |  |  | 					"instance", "0", | 
					
						
							|  |  |  | 					"job", "app-server", | 
					
						
							|  |  |  | 				), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 				F: 1, | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	baseTime := time.Unix(0, 0) | 
					
						
							|  |  |  | 	for i, result := range results { | 
					
						
							|  |  |  | 		t.Logf("case %d", i) | 
					
						
							|  |  |  | 		evalTime := baseTime.Add(time.Duration(i) * time.Minute) | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 		result[0].T = timestamp.FromTime(evalTime) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 		res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0) | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
 | 
					
						
							|  |  |  | 		for _, smpl := range res { | 
					
						
							|  |  |  | 			smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 			if smplName == "ALERTS" { | 
					
						
							|  |  |  | 				filteredRes = append(filteredRes, smpl) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							|  |  |  | 				require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		require.Equal(t, result, filteredRes) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	evalTime := baseTime.Add(time.Duration(len(results)) * time.Minute) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0) | 
					
						
							| 
									
										
										
										
											2023-01-19 17:36:01 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	require.Equal(t, 0, len(res)) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-01-19 18:53:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestPendingAndKeepFiringFor(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	storage := promql.LoadedStorage(t, ` | 
					
						
							| 
									
										
										
										
											2023-01-19 18:53:42 +08:00
										 |  |  | 		load 1m | 
					
						
							|  |  |  | 			http_requests{job="app-server", instance="0"}	75 10x10 | 
					
						
							|  |  |  | 	`) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	t.Cleanup(func() { storage.Close() }) | 
					
						
							| 
									
										
										
										
											2023-01-19 18:53:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	expr, err := parser.ParseExpr(`http_requests > 50`) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		"HTTPRequestRateHigh", | 
					
						
							|  |  |  | 		expr, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							|  |  |  | 		time.Minute, | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result := promql.Sample{ | 
					
						
							|  |  |  | 		Metric: labels.FromStrings( | 
					
						
							|  |  |  | 			"__name__", "ALERTS", | 
					
						
							|  |  |  | 			"alertname", "HTTPRequestRateHigh", | 
					
						
							|  |  |  | 			"alertstate", "pending", | 
					
						
							|  |  |  | 			"instance", "0", | 
					
						
							|  |  |  | 			"job", "app-server", | 
					
						
							|  |  |  | 		), | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 		F: 1, | 
					
						
							| 
									
										
										
										
											2023-01-19 18:53:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	baseTime := time.Unix(0, 0) | 
					
						
							| 
									
										
											  
											
												promql: Separate `Point` into `FPoint` and `HPoint`
In other words: Instead of having a “polymorphous” `Point` that can
either contain a float value or a histogram value, use an `FPoint` for
floats and an `HPoint` for histograms.
This seemingly small change has a _lot_ of repercussions throughout
the codebase.
The idea here is to avoid the increase in size of `Point` arrays that
happened after native histograms had been added.
The higher-level data structures (`Sample`, `Series`, etc.) are still
“polymorphous”. The same idea could be applied to them, but at each
step the trade-offs needed to be evaluated.
The idea with this change is to do the minimum necessary to get back
to pre-histogram performance for functions that do not touch
histograms. Here are comparisons for the `changes` function. The test
data doesn't include histograms yet. Ideally, there would be no change
in the benchmark result at all.
First runtime v2.39 compared to directly prior to this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     542µs ± 1%  +38.58%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     617µs ± 2%  +36.48%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.36ms ± 2%  +21.58%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    8.94ms ± 1%  +14.21%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.30ms ± 1%  +10.67%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.10ms ± 1%  +11.82%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    11.8ms ± 1%  +12.50%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    87.4ms ± 1%  +12.63%  (p=0.000 n=9+9)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    32.8ms ± 1%   +8.01%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.6ms ± 2%   +9.64%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     117ms ± 1%  +11.69%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     876ms ± 1%  +11.83%  (p=0.000 n=9+10)
```
And then runtime v2.39 compared to after this commit:
```
name                                                  old time/op    new time/op    delta
RangeQuery/expr=changes(a_one[1d]),steps=1-16            391µs ± 2%     547µs ± 1%  +39.84%  (p=0.000 n=9+8)
RangeQuery/expr=changes(a_one[1d]),steps=10-16           452µs ± 2%     616µs ± 2%  +36.15%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_one[1d]),steps=100-16         1.12ms ± 1%    1.26ms ± 1%  +12.20%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_one[1d]),steps=1000-16        7.83ms ± 1%    7.95ms ± 1%   +1.59%  (p=0.000 n=10+8)
RangeQuery/expr=changes(a_ten[1d]),steps=1-16           2.98ms ± 0%    3.38ms ± 2%  +13.49%  (p=0.000 n=9+10)
RangeQuery/expr=changes(a_ten[1d]),steps=10-16          3.66ms ± 1%    4.02ms ± 1%   +9.80%  (p=0.000 n=10+9)
RangeQuery/expr=changes(a_ten[1d]),steps=100-16         10.5ms ± 0%    10.8ms ± 1%   +3.08%  (p=0.000 n=8+10)
RangeQuery/expr=changes(a_ten[1d]),steps=1000-16        77.6ms ± 1%    78.1ms ± 1%   +0.58%  (p=0.035 n=9+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1-16       30.4ms ± 2%    33.5ms ± 4%  +10.18%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=10-16      37.1ms ± 2%    40.0ms ± 1%   +7.98%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=100-16      105ms ± 1%     107ms ± 1%   +1.92%  (p=0.000 n=10+10)
RangeQuery/expr=changes(a_hundred[1d]),steps=1000-16     783ms ± 3%     775ms ± 1%   -1.02%  (p=0.019 n=9+9)
```
In summary, the runtime doesn't really improve with this change for
queries with just a few steps. For queries with many steps, this
commit essentially reinstates the old performance. This is good
because the many-step queries are the one that matter most (longest
absolute runtime).
In terms of allocations, though, this commit doesn't make a dent at
all (numbers not shown). The reason is that most of the allocations
happen in the sampleRingIterator (in the storage package), which has
to be addressed in a separate commit.
Signed-off-by: beorn7 <beorn@grafana.com>
											
										 
											2022-10-28 22:58:40 +08:00
										 |  |  | 	result.T = timestamp.FromTime(baseTime) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	res, err := rule.Eval(context.TODO(), baseTime, EngineQueryFunc(testEngine, storage), nil, 0) | 
					
						
							| 
									
										
										
										
											2023-01-19 18:53:42 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require.Len(t, res, 2) | 
					
						
							|  |  |  | 	for _, smpl := range res { | 
					
						
							|  |  |  | 		smplName := smpl.Metric.Get("__name__") | 
					
						
							|  |  |  | 		if smplName == "ALERTS" { | 
					
						
							|  |  |  | 			require.Equal(t, result, smpl) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'.
 | 
					
						
							|  |  |  | 			require.Equal(t, "ALERTS_FOR_STATE", smplName) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	evalTime := baseTime.Add(time.Minute) | 
					
						
							| 
									
										
										
										
											2023-08-19 02:48:59 +08:00
										 |  |  | 	res, err = rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0) | 
					
						
							| 
									
										
										
										
											2023-01-19 18:53:42 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	require.Equal(t, 0, len(res)) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-01-26 19:10:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 16:53:49 +08:00
										 |  |  | // TestAlertingEvalWithOrigin checks that the alerting rule details are passed through the context.
 | 
					
						
							| 
									
										
										
										
											2023-01-09 16:14:37 +08:00
										 |  |  | func TestAlertingEvalWithOrigin(t *testing.T) { | 
					
						
							|  |  |  | 	ctx := context.Background() | 
					
						
							|  |  |  | 	now := time.Now() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 16:53:49 +08:00
										 |  |  | 	const ( | 
					
						
							|  |  |  | 		name  = "my-recording-rule" | 
					
						
							|  |  |  | 		query = `count(metric{foo="bar"}) > 0` | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		detail RuleDetail | 
					
						
							|  |  |  | 		lbs    = labels.FromStrings("test", "test") | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2023-01-09 16:14:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	expr, err := parser.ParseExpr(query) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rule := NewAlertingRule( | 
					
						
							|  |  |  | 		name, | 
					
						
							|  |  |  | 		expr, | 
					
						
							| 
									
										
										
										
											2023-01-26 19:21:50 +08:00
										 |  |  | 		time.Second, | 
					
						
							| 
									
										
										
										
											2023-01-09 16:14:37 +08:00
										 |  |  | 		time.Minute, | 
					
						
							| 
									
										
										
										
											2023-01-09 16:53:49 +08:00
										 |  |  | 		lbs, | 
					
						
							| 
									
										
										
										
											2023-02-22 23:13:31 +08:00
										 |  |  | 		labels.EmptyLabels(), | 
					
						
							|  |  |  | 		labels.EmptyLabels(), | 
					
						
							| 
									
										
										
										
											2023-01-09 16:14:37 +08:00
										 |  |  | 		"", | 
					
						
							|  |  |  | 		true, log.NewNopLogger(), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, err = rule.Eval(ctx, now, func(ctx context.Context, qs string, _ time.Time) (promql.Vector, error) { | 
					
						
							|  |  |  | 		detail = FromOriginContext(ctx) | 
					
						
							|  |  |  | 		return nil, nil | 
					
						
							|  |  |  | 	}, nil, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-01-09 16:53:49 +08:00
										 |  |  | 	require.Equal(t, detail, NewRuleDetail(rule)) | 
					
						
							| 
									
										
										
										
											2023-01-09 16:14:37 +08:00
										 |  |  | } |