Improve performance of WithLabelValues(...)

The slice with variadic arguments passed to MetricVec.WithLabelValues()
was escaping to heap. This change fixes that by performing a copy of the
slice before passing it to fmt.Errorf(), which is where the slice was
escaping. This keeps the hot path without that allocation.

Meaningful benchmark results (skipping ~0 CPU and 0 alloc ones):

                                                               │    old.txt    │               new.txt                │
                                                               │    sec/op     │    sec/op     vs base                │
Counter/With_Label_Values-16                                     108.00n ±  6%   58.06n ±  1%  -46.24% (p=0.000 n=10)
Counter/With_Label_Values_and_Constraint-16                       174.5n ± 15%   136.8n ±  6%  -21.63% (p=0.000 n=10)
Counter/With_triple_Label_Values-16                               309.3n ± 12%   172.9n ±  1%  -44.08% (p=0.000 n=10)
Counter/With_triple_Label_Values_and_Constraint-16                591.5n ± 11%   418.9n ±  3%  -29.17% (p=0.000 n=10)
Counter/With_repeated_Label_Values-16                             212.9n ± 10%   116.8n ± 23%  -45.16% (p=0.000 n=10)
Counter/With_repeated_Label_Values_and_Constraint-16              406.2n ± 14%   275.1n ±  4%  -32.30% (p=0.000 n=10)
CounterWithLabelValuesConcurrent-16                               85.45n ±  2%   89.09n ±  2%   +4.26% (p=0.003 n=10)

                                                               │    old.txt     │                  new.txt                  │
                                                               │      B/op      │     B/op      vs base                     │
Counter/With_Label_Values-16                                       48.00 ± 0%        0.00 ± 0%  -100.00% (p=0.000 n=10)
Counter/With_Label_Values_and_Constraint-16                        96.00 ± 0%       48.00 ± 0%   -50.00% (p=0.000 n=10)
Counter/With_triple_Label_Values-16                                144.0 ± 0%         0.0 ± 0%  -100.00% (p=0.000 n=10)
Counter/With_triple_Label_Values_and_Constraint-16                 288.0 ± 0%       144.0 ± 0%   -50.00% (p=0.000 n=10)
Counter/With_repeated_Label_Values-16                              96.00 ± 0%        0.00 ± 0%  -100.00% (p=0.000 n=10)
Counter/With_repeated_Label_Values_and_Constraint-16              192.00 ± 0%       96.00 ± 0%   -50.00% (p=0.000 n=10)
CounterWithLabelValuesConcurrent-16                                48.00 ± 0%        0.00 ± 0%  -100.00% (p=0.000 n=10)

                                                               │   old.txt    │                 new.txt                 │
                                                               │  allocs/op   │ allocs/op   vs base                     │
Counter/With_Label_Values-16                                     1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)
Counter/With_Label_Values_and_Constraint-16                      2.000 ± 0%     1.000 ± 0%   -50.00% (p=0.000 n=10)
Counter/With_triple_Label_Values-16                              3.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)
Counter/With_triple_Label_Values_and_Constraint-16               6.000 ± 0%     3.000 ± 0%   -50.00% (p=0.000 n=10)
Counter/With_repeated_Label_Values-16                            2.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)
Counter/With_repeated_Label_Values_and_Constraint-16             4.000 ± 0%     2.000 ± 0%   -50.00% (p=0.000 n=10)
CounterWithLabelValuesConcurrent-16                              1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)

Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
This commit is contained in:
Oleg Zaytsev 2023-10-04 18:09:15 +02:00
parent 4c10365899
commit 005d8de006
No known key found for this signature in database
GPG Key ID: 7E9FE9FD48F512EF
1 changed files with 2 additions and 0 deletions

View File

@ -165,6 +165,8 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error {
func validateLabelValues(vals []string, expectedNumberOfValues int) error { func validateLabelValues(vals []string, expectedNumberOfValues int) error {
if len(vals) != expectedNumberOfValues { if len(vals) != expectedNumberOfValues {
// The call below makes vals escape, copy them to avoid that.
vals := append([]string(nil), vals...)
return fmt.Errorf( return fmt.Errorf(
"%w: expected %d label values but got %d in %#v", "%w: expected %d label values but got %d in %#v",
errInconsistentCardinality, expectedNumberOfValues, errInconsistentCardinality, expectedNumberOfValues,