Skip to content

Commit 0a5425f

Browse files
committed
prometheus_text_format: Avoid allocation in has_special_char/1
`prometheus_text_format:has_special_char/1` is called very often when a registry contains many metrics with label pairs. We can use `binary:match/2` to search within a label binary for the special characters (newline, backslash and double-quote) without allocation. The old code using binary match syntax creates a match context every time the function is called (except, not recursion - then the match context is reused). A match context allocates 5 words to the process heap when it is created. When matching many many binaries this scales to create a noticeable amount of short-lived garbage. In comparison `binary:match/2` with a precompiled match pattern does not allocate. The BIF for it is also very well optimized, using `memchr` since OTP 22.
1 parent a4f1432 commit 0a5425f

File tree

1 file changed

+9
-6
lines changed

1 file changed

+9
-6
lines changed

src/formats/prometheus_text_format.erl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,15 @@ escape_label_char(X) ->
289289

290290
?DOC(false).
291291
-spec has_special_char(binary()) -> boolean().
292-
has_special_char(<<C:8, _/bitstring>>) when C =:= $\\; C =:= $\n; C =:= $" ->
293-
true;
294-
has_special_char(<<_:8, Rest/bitstring>>) ->
295-
has_special_char(Rest);
296-
has_special_char(<<>>) ->
297-
false.
292+
has_special_char(Subject) when is_binary(Subject) ->
293+
case get(prometheus_text_format_escape_pattern) of
294+
undefined ->
295+
Pat = binary:compile_pattern([<<$\\>>, <<$\n>>, <<$">>]),
296+
put(prometheus_text_format_escape_pattern, Pat),
297+
has_special_char(Subject);
298+
Pat ->
299+
binary:match(Subject, Pat) /= nomatch
300+
end.
298301

299302
?DOC(false).
300303
escape_string(Fun, Str) when is_binary(Str) ->

0 commit comments

Comments
 (0)