Skip to content

Avoid redundant slice and map allocations in exporters/prometheus - #9248

Open
dashpole wants to merge 2 commits into
open-telemetry:mainfrom
dashpole:prom-exporter-attr-allocs
Open

dashpole wants to merge 2 commits into
open-telemetry:mainfrom
dashpole:prom-exporter-attr-allocs

Conversation

@dashpole

Copy link
Copy Markdown
Contributor

Reduce per-scrape allocations when translating data point and instrumentation scope attributes in exporters/prometheus:

  • Replace the unconditional keysMap := make(map[string][]string) and per-attribute []string{kv.Value.String()} allocations in getAttrs and getScopeAttrs with direct slice appends in attrs.Iter() order, allocating a collision map (dups map[int][]string) only when sanitized label names collide.
  • Introduce getAttrsWithKV and appendScopeAttrs so data point keys/values slices are pre-sized to attrs.Len() + len(kv.keys) (or reuse kv.keys/kv.vals directly when attrs.Len() == 0) and scope attributes are appended directly into kv.
  • Pre-size positiveBuckets and negativeBuckets in addExponentialHistogramMetric and labels in attributesToLabels.

Benchmark Output

goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/exporters/prometheus
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
                                     │   base.txt    │               new.txt               │
                                     │    sec/op     │    sec/op     vs base               │
Collect1/ObservabilityDisabled-24       182.9µ ± 78%   177.2µ ±  4%        ~ (p=0.065 n=6)
Collect1/ObservabilityEnabled-24        191.7µ ± 71%   174.9µ ±  6%   -8.75% (p=0.009 n=6)
Collect10/ObservabilityDisabled-24      1.327m ± 59%   1.196m ±  4%   -9.88% (p=0.004 n=6)
Collect10/ObservabilityEnabled-24       1.312m ± 74%   1.205m ±  9%   -8.12% (p=0.041 n=6)
Collect100/ObservabilityDisabled-24     12.03m ± 46%   10.73m ± 29%  -10.77% (p=0.041 n=6)
Collect100/ObservabilityEnabled-24      11.73m ±  6%   10.35m ±  8%  -11.73% (p=0.004 n=6)
Collect1000/ObservabilityDisabled-24   102.14m ±  7%   91.20m ± 10%  -10.72% (p=0.009 n=6)
Collect1000/ObservabilityEnabled-24    107.42m ± 10%   90.21m ± 20%  -16.02% (p=0.026 n=6)
geomean                                 4.187m         3.770m         -9.95%

                                     │   base.txt   │              new.txt               │
                                     │     B/op     │     B/op      vs base              │
Collect1/ObservabilityDisabled-24      62.67Ki ± 0%   61.28Ki ± 0%  -2.22% (p=0.002 n=6)
Collect1/ObservabilityEnabled-24       62.83Ki ± 0%   61.43Ki ± 0%  -2.24% (p=0.002 n=6)
Collect10/ObservabilityDisabled-24     358.5Ki ± 0%   345.1Ki ± 0%  -3.73% (p=0.002 n=6)
Collect10/ObservabilityEnabled-24      359.7Ki ± 0%   346.3Ki ± 0%  -3.72% (p=0.002 n=6)
Collect100/ObservabilityDisabled-24    3.293Mi ± 0%   3.163Mi ± 0%  -3.95% (p=0.002 n=6)
Collect100/ObservabilityEnabled-24     3.299Mi ± 0%   3.169Mi ± 0%  -3.96% (p=0.002 n=6)
Collect1000/ObservabilityDisabled-24   32.61Mi ± 0%   31.30Mi ± 0%  -4.04% (p=0.002 n=6)
Collect1000/ObservabilityEnabled-24    32.64Mi ± 0%   31.30Mi ± 0%  -4.09% (p=0.002 n=6)
geomean                                1.233Mi        1.190Mi       -3.49%

                                     │  base.txt   │              new.txt              │
                                     │  allocs/op  │  allocs/op   vs base              │
Collect1/ObservabilityDisabled-24       389.0 ± 0%    351.0 ± 0%  -9.77% (p=0.002 n=6)
Collect1/ObservabilityEnabled-24        389.0 ± 0%    351.0 ± 0%  -9.77% (p=0.002 n=6)
Collect10/ObservabilityDisabled-24     4.062k ± 0%   3.709k ± 0%  -8.69% (p=0.002 n=6)
Collect10/ObservabilityEnabled-24      4.064k ± 0%   3.711k ± 0%  -8.69% (p=0.002 n=6)
Collect100/ObservabilityDisabled-24    41.38k ± 0%   37.88k ± 0%  -8.47% (p=0.002 n=6)
Collect100/ObservabilityEnabled-24     41.39k ± 0%   37.88k ± 0%  -8.47% (p=0.002 n=6)
Collect1000/ObservabilityDisabled-24   414.4k ± 0%   379.1k ± 0%  -8.51% (p=0.002 n=6)
Collect1000/ObservabilityEnabled-24    414.7k ± 0%   379.1k ± 0%  -8.56% (p=0.002 n=6)
geomean                                12.83k        11.69k       -8.87%

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on maintainers · refreshed 2026-10-23 20:22 UTC

Merge when ready.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

@codecov

codecov Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.4%. Comparing base (d376be4) to head (1ba6f67).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@          Coverage Diff           @@
##            main   #9248    +/-   ##
======================================
  Coverage   89.4%   89.4%            
======================================
  Files        345     346     +1     
  Lines      22687   22886   +199     
======================================
+ Hits       20289   20481   +192     
- Misses      2398    2405     +7     
Files with missing lines Coverage Δ
exporters/prometheus/exporter.go 93.6% <100.0%> (+0.5%) ⬆️

... and 8 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dashpole
dashpole marked this pull request as ready for review October 20, 2026 20:03
@dashpole dashpole added the Skip Changelog PRs that do not require a CHANGELOG.md entry label Oct 20, 2026
@opentelemetry-pr-dashboard
opentelemetry-pr-dashboard Bot requested a balanced review from Copilot October 20, 2026 20:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Both attribute translation helpers introduce quadratic collision-detection work for larger attribute sets.

1 open issue
What changed in this PR

Reduces per-scrape allocations in the Prometheus exporter’s attribute and histogram translation.

Changes:

  • Reuses or pre-sizes label slices and allocates collision storage only when needed.
  • Pre-sizes histogram bucket and exemplar label maps.
  • Adds sanitized-label collision tests.
File Description
exporters/​prometheus/​exporter.go Optimizes attribute translation and collection allocations.
exporters/​prometheus/​exporter_test.go Tests data-point and scope label collisions.

Review effort: Balanced

Comment thread exporters/prometheus/exporter.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused optimizations preserve existing behavior, with regression coverage for both collision-detection paths.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Skip Changelog PRs that do not require a CHANGELOG.md entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants