-
Notifications
You must be signed in to change notification settings - Fork 9.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimise relabeling by re-using memory #11147
Conversation
Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
Saves memory allocations. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This reduces memory allocations where the caller has a suitable slice available. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
To reduce memory allocations. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
Restore original behaviour in PopulateLabels, where we must not overwrite the input set. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
Use a stack-based array for up to 16 source labels, which will be the vast majority of cases. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
I pushed another commit which re-does "re-use source values slice" in a simpler way, and reduces allocations by 1 more. |
@@ -192,24 +192,29 @@ func (re Regexp) String() string { | |||
// are applied in order of input. | |||
// If a label set is dropped, nil is returned. | |||
// May return the input labelSet modified. | |||
func Process(labels labels.Labels, cfgs ...*Config) labels.Labels { | |||
func Process(lbls labels.Labels, cfgs ...*Config) labels.Labels { | |||
lb := labels.NewBuilder(nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like another interface called ProcessWithBuilder
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK; is that relevant to this PR?
If not, it would belong in a separate PR with its own justification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about using a pool of Builders here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That could also be done inside Process
without changing the api.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a comment
var va [16]string | ||
values := va[:0] | ||
if len(cfg.SourceLabels) > cap(values) { | ||
values = make([]string, 0, len(cfg.SourceLabels)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this better than the previous?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, would re-using the values
slice between the relabel
calls make it better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For relabeling rules with up to 16 source labels (surely most real-life examples), it uses an array on the stack, thus performs no heap allocation.
I tried re-using the slice; see 135e517. It is more complicated and does one allocation in every case, compared to zero in most cases.
* model/relabel: Add benchmark Signed-off-by: Bryan Boreham <bjboreham@gmail.com> * model/relabel: re-use Builder across relabels Saves memory allocations. Signed-off-by: Bryan Boreham <bjboreham@gmail.com> * labels.Builder: allow re-use of result slice This reduces memory allocations where the caller has a suitable slice available. Signed-off-by: Bryan Boreham <bjboreham@gmail.com> * model/relabel: re-use source values slice To reduce memory allocations. Signed-off-by: Bryan Boreham <bjboreham@gmail.com> * Unwind one change causing test failures Restore original behaviour in PopulateLabels, where we must not overwrite the input set. Signed-off-by: Bryan Boreham <bjboreham@gmail.com> * relabel: simplify values optimisation Use a stack-based array for up to 16 source labels, which will be the vast majority of cases. Signed-off-by: Bryan Boreham <bjboreham@gmail.com> * lint Signed-off-by: Bryan Boreham <bjboreham@gmail.com> Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
The benchmark name is BenchmarkApplyRelabelConfigs/kubernetes This benchmark has been copied from https://github.com/Arnoways/prometheus/blob/d521933053bdf68d252e365da9376706d04addcc/model/relabel/relabel_test.go#L505 See also prometheus/prometheus#11147
The benchmark name is BenchmarkApplyRelabelConfigs/kubernetes This benchmark has been copied from https://github.com/Arnoways/prometheus/blob/d521933053bdf68d252e365da9376706d04addcc/model/relabel/relabel_test.go#L505 See also prometheus/prometheus#11147
Relabeling can be a large portion of Prometheus memory allocation, and hence overall performance.
Especially relabeling in service discovery.
Since relabelling works by applying different rules to the same label set, we can re-use slices and greatly reduce memory allocation. Also re-use the Builder itself since
NewBuilder()
makes some speculative allocations.The benchmark is somewhat lengthy, due to including realistic data.