-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
I was going to write a blog about the metric SDK optimization work, and was working on updating https://github.com/promlabs/prometheus-otel-benchmarks to demonstrate the improvements. I tried adding a benchmark that follows our best practices for performance in promlabs/prometheus-otel-benchmarks@2c01c31, but I still see an allocation in attribute.NewSet.
I confirmed that is the case in the BenchmarkNewSet benchmark here:
BenchmarkNewSet 233108 503.3 ns/op 448 B/op 1 allocs/op
Unfortunately, this mostly makes the optimizations in the metrics SDK a bit irrelevant. A counter increment is now ~60 ns and has no allocations, but creating the attribute set to pass to it is 500ns with an allocation. The SDK can be used in a performant way, but only if the user precomputes all commonly used attribute sets.
Ideas
I was playing around with some ideas, but I haven't been able to get any to work yet.
One idea is to introduce a constructor for attribute.Set that accepts another attribute.Set as storage:
func NewReusedSet(existing *Set, kvs KeyValue...) *Set {}The idea would be that the user can create (yet another) sync.Pool, and manage the re-use of sets with the same number of underlying attributes. This has the advantage of providing users a way to re-use sets without the risk of a different library causing issues.
Another idea is to add Set.Free():
// Free releases the underlying storage of the Set to allow it to be re-used by subsequent NewSet calls.
func (s *Set) Free() {}which puts the set in a pool of sets with the same number of attributes. I prototyped this here: main...dashpole:opentelemetry-go:noalloc_set, but wasn't able to get it to work properly, while still keeping Set comparable.
I'm looking for other ideas as well. I think this is a big enough performance penalty for us to even consider a v2 of the attributes package, if necessary. Currently, writing performant metrics code is quite onerous: https://github.com/open-telemetry/opentelemetry-go/blob/main/CONTRIBUTING.md#attribute-and-option-allocation-management, and this may be an opportunity to address that as well.
"Bound" instruments could also help here, but will miss a number of common use-cases for metrics libraries, so I don't consider that a complete solution.