client_golang icon indicating copy to clipboard operation
client_golang copied to clipboard

Improve Performance of MakeLabelPairs

Open kgeckhart opened this issue 9 months ago • 11 comments

This PR refactors the internals of the Desc to create an optimized version of MakeLabelPairs by replacing the constLabels with a sorted labelPairs containing constant labels and variable labels. The Desc also carries an extra map so it is possible to insert the labelValues in to the proper sorted index on output. Benchmark results,

                             │ baseline.txt │               new.txt                │
                             │    sec/op    │    sec/op     vs base                │
_MakeLabelPairs/1_label-11      94.25n ± 1%   47.06n ±  1%  -50.07% (p=0.000 n=10)
_MakeLabelPairs/3_labels-11     262.9n ± 1%   119.8n ±  0%  -54.44% (p=0.000 n=10)
_MakeLabelPairs/10_labels-11   1005.0n ± 0%   372.9n ± 10%  -62.89% (p=0.000 n=10)
geomean                         292.0n        128.1n        -56.13%

                             │ baseline.txt │              new.txt               │
                             │     B/op     │    B/op     vs base                │
_MakeLabelPairs/1_label-11      136.00 ± 0%   96.00 ± 0%  -29.41% (p=0.000 n=10)
_MakeLabelPairs/3_labels-11      360.0 ± 0%   288.0 ± 0%  -20.00% (p=0.000 n=10)
_MakeLabelPairs/10_labels-11    1048.0 ± 0%   880.0 ± 0%  -16.03% (p=0.000 n=10)
geomean                          371.6        289.8       -22.02%

                             │ baseline.txt │              new.txt               │
                             │  allocs/op   │ allocs/op   vs base                │
_MakeLabelPairs/1_label-11       5.000 ± 0%   3.000 ± 0%  -40.00% (p=0.000 n=10)
_MakeLabelPairs/3_labels-11     11.000 ± 0%   7.000 ± 0%  -36.36% (p=0.000 n=10)
_MakeLabelPairs/10_labels-11     29.00 ± 0%   19.00 ± 0%  -34.48% (p=0.000 n=10)
geomean                          11.68        7.362       -36.99%

No longer sorting the immutable set of label names drops CPU usage dramatically and some memory. There's also a further benefit to memory by calling proto.String only once for the variable label names.

The tradeoff is a little bit more overhead in the Desc to store the full labelPairs and an index lookup map. I think this is a fair tradeoff to make because a single Desc instance is likely to be used for numerous calls to MakeLabelPairs.

Related to: https://github.com/prometheus/client_golang/issues/1702

kgeckhart avatar Feb 12 '25 21:02 kgeckhart