feat(label_namer): skip allocation for already-compliant labels#69
Open
aknuds1 wants to merge 2 commits into
Open
feat(label_namer): skip allocation for already-compliant labels#69aknuds1 wants to merge 2 commits into
aknuds1 wants to merge 2 commits into
Conversation
edb64cf to
f1569da
Compare
f1569da to
25bd9e7
Compare
Add a single forward-scan predicate canFastPathLabel that detects when LabelNamer.Build would return its input unchanged. On a hit, Build returns the input string directly with zero heap allocations, addressing the "already-compliant labels are wastefully reallocated" half of #68. The predicate covers the four LabelNamer config combinations and the reserved-label round-trip (__...__) where the inner range sanitizes to itself. A property test asserts predicate-Build agreement across every case in labelTestCases × the four configs; testing.AllocsPerRun confirms the fast path is allocation-free. Benchmarks on Apple M4 Pro: already-valid label: 15.77 ns/op 0 B/op 0 allocs/op LabelWithCapitalLetters: 18.67 ns/op 0 B/op 0 allocs/op _label_starting_with_underscore (default config): 25.27 ns/op 0 B/op 0 allocs/op Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
sanitizeLabelName's reserved-label branch returned
"__" + b.String() + "__", which produced two allocations: one for the
builder buffer and one for the string concatenation that wraps it.
Write the "__" wrappers directly into the strings.Builder before and
after the sanitize loop instead; b.Grow(nameLength) already accounts
for the worst-case length (stripped inner ≤ nameLength-4, plus 4
wrapper bytes).
Add "__reserved__label__name__" as a benchmark input so the change is
visible.
benchstat (Apple M4 Pro, -count=10):
reserved_label: 84.71 ns/op → 66.84 ns/op (-21.1%)
56 B/op → 32 B/op (-42.9%)
2 allocs/op → 1 allocs/op (-50.0%)
Other rows unchanged.
Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
25bd9e7 to
f06b2ef
Compare
dashpole
reviewed
May 20, 2026
| // canFastPathLabel reports whether LabelNamer.Build would return label unchanged when UTF8Allowed is false. | ||
| // When it returns true, the label can be returned directly. The predicate must remain | ||
| // consistent with sanitizeLabelName and the post-sanitize prefix logic in LabelNamer.Build. | ||
| func canFastPathLabel(label string, preserveMultipleUnderscores, underscoreLabelSanitization bool) bool { |
Contributor
There was a problem hiding this comment.
Should we be delegating any of this logic to the prometheus/common validators? E.g. https://github.com/prometheus/common/blob/0f3c348807322ea84d92fc7688b1b37a08e17d1f/model/metric.go#L175
Contributor
Author
There was a problem hiding this comment.
Having a look, thanks.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add a single forward-scan predicate
canFastPathLabelthat detects whenLabelNamer.Buildwould return its input unchanged. On a hit,Buildreturns the input string directly with zero heap allocations, addressing the "already-compliant labels are wastefully reallocated" half of #68.The predicate covers the four
LabelNamerconfig combinations and the reserved-label round-trip (...) where the inner range sanitizes to itself. A property test asserts predicate-Buildagreement across every case inlabelTestCases× the four configs;testing.AllocsPerRunconfirms the fast path is allocation-free.Please note that there is one case that regresses in CPU utilization (+20.56%, ~18 ns):
NormalizeLabel/label_with_foreign_characters. I think foreign characters in OTel metric attributes, while translation is enabled, should be an unusual case though, and the -30% geomean makes the tradeoff worth it.I realized this simpler optimization could be made while reviewing #68.