Skip to content

test: focus PR benchmarks on client_java and measure label lookups - #2468

Merged
zeitlinger merged 3 commits into
mainfrom
bench/pr-client-only-label-lookup
Sep 15, 2026
Merged

zeitlinger merged 3 commits into
mainfrom
bench/pr-client-only-label-lookup

Conversation

@zeitlinger

Copy link
Copy Markdown
Member

Summary

Benchmark-only follow-up for the release review; no production metric changes.

  • Restrict both base and head PR benchmark runs to client_java counter/histogram methods.
    OpenTelemetry, Codahale, and legacy simpleclient comparisons remain in full/local/nightly runs.
    Keep all client_java exposition benchmarks, including OpenMetrics.
  • Add repeated existing-label lookup + increment benchmarks and cached-data-point baselines,
    with one-thread and four-thread variants. One invocation is one metric update.
  • Report GC profiler allocation in B/op separately from throughput, including descriptive
    base/head allocation deltas only when configurations match.
  • Add selection/report regression tests and run benchmark tooling tests in lint CI.
  • Document operation units and the new benchmark workflow.

Related PR

Label lookup optimization #2442 is pending this
benchmark infrastructure. After this lands, update that branch and rerun the benchmarks so base and
head contain identical lookup benchmark code. The new methods in this PR itself have head-only
results and do not establish the optimization's benefit.

Validation

  • mise run lint:fix — passed; formatter changes retained.
  • mise run test — passed.
  • All three benchmark tooling test scripts — 24 tests passed.
  • mise run build -- -DskipITs=true — passed.
  • Plain mise run build compiled the benchmark module, but Docker-backed integration tests ran
    despite -DskipTests and failed because no Docker environment was available.
  • JMH listing with each workflow pattern confirmed client_java-only selection and retained
    OpenMetrics/Prometheus exposition cases.
  • All four new benchmarks completed with GC profiling: 1 fork, 2 x 1s warmups, 3 x 1s measurements,
    JDK 25.0.3, -Xms128m -Xmx256m. This was a smoke test on a shared development host, not a
    controlled base/head performance comparison. Repeated lookup reported about 64 B/update;
    cached increments were near zero.
  • Generated the Markdown report from real smoke-run JSON and checked allocation output.
  • git diff --check — passed.

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
@zeitlinger

Copy link
Copy Markdown
Member Author

The histogram timeout was investigated separately from this benchmark work.
#2471 reproduces and fixes a Buffer
generation-handoff race capable of producing the same timeout.

The forced interleaving fails on the old implementation after five seconds, then passes with the
fix. Both regression cases plus the original multithreaded histogram test passed 450 local
executions across 1, 2, and 4 configured processors; full unit tests and core coverage checks also
passed. This proves the race, though not the exact interleaving of this historical CI failure.

This PR remains benchmark-only. Once the correctness fix lands, update/retest this branch rather
than increasing the timeout or weakening the test.

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

Benchmark run succeeded for e45bd731daadc093c8f2294618633c6edefb3b8b.

Prometheus Java Client Benchmarks

Run Information

  • Date: 2026-09-15T11:56:10Z
  • Commit: e45bd73
  • JDK: 25.0.3 (OpenJDK 64-Bit Server VM)
  • Benchmark config: 3 fork(s), 3 warmup, 5 measurement, 1/4 threads
  • Hardware: AMD EPYC 9V74 80-Core Processor, 4 cores, 16 GB RAM
  • OS: Linux 6.17.0-1022-azure

Comparison with base

  • Head: e45bd73
  • Base: 02622cb
  • Metric direction: Throughput scores are higher-is-better; positive Head vs base deltas indicate faster performance.
  • Note: Base and head are compared on the same runner within each topic.
Benchmark PR Base Head vs base Regression verdict
CounterBenchmark.prometheusAdd 51.50K 50.94K +1.1% within noise
CounterBenchmark.prometheusInc 64.08K 66.47K -3.6% within noise
CounterBenchmark.prometheusNoLabelsInc 56.10K 56.41K -0.5% within noise
HistogramBenchmark.prometheusClassic 5.46K 5.35K +2.0% within noise
HistogramBenchmark.prometheusClassicPerThread 17.01K 17.00K +0.0% within noise
HistogramBenchmark.prometheusClassicSingleThread 6.95K 6.93K +0.3% within noise
HistogramBenchmark.prometheusNative 3.78K 3.72K +1.8% within noise
HistogramTextFormatBenchmark.openMetricsWriteToNull 18.12K 18.16K -0.2% within noise
HistogramTextFormatBenchmark.prometheusWriteToNull 18.17K 18.26K -0.5% within noise
TextFormatUtilBenchmark.openMetricsWriteToByteArray 288.21K 287.57K +0.2% within noise
TextFormatUtilBenchmark.openMetricsWriteToNull 287.95K 288.32K -0.1% within noise
TextFormatUtilBenchmark.prometheusWriteToByteArray 307.06K 310.82K -1.2% within noise
TextFormatUtilBenchmark.prometheusWriteToNull 310.09K 313.99K -1.2% within noise
  • Benchmarks only in PR results (listed separately below): CounterBenchmark.prometheusCachedLabelValuesInc, CounterBenchmark.prometheusCachedLabelValuesIncSingleThread, CounterBenchmark.prometheusLabelValuesInc, CounterBenchmark.prometheusLabelValuesIncSingleThread

Results for PR head

CounterBenchmark

Benchmark Score Error Units
prometheusInc 64.08K ± 4.65K ops/s
prometheusNoLabelsInc 56.10K ± 833.35 ops/s
prometheusAdd 51.50K ± 253.37 ops/s

HistogramBenchmark

Benchmark Score Error Units
prometheusClassicPerThread 17.01K ± 24.65 ops/s
prometheusClassicSingleThread 6.95K ± 27.50 ops/s
prometheusClassic 5.46K ± 1.04K ops/s
prometheusNative 3.78K ± 422.26 ops/s

HistogramTextFormatBenchmark

Benchmark Score Error Units
prometheusWriteToNull 18.17K ± 83.73 ops/s
openMetricsWriteToNull 18.12K ± 90.42 ops/s

TextFormatUtilBenchmark

Benchmark Score Error Units
prometheusWriteToNull 310.09K ± 3.03K ops/s
prometheusWriteToByteArray 307.06K ± 5.49K ops/s
openMetricsWriteToByteArray 288.21K ± 2.90K ops/s
openMetricsWriteToNull 287.95K ± 4.48K ops/s

New benchmarks in PR head

These benchmarks have no base counterpart; scores are descriptive only and have no regression verdict.

Benchmark Score Error Units
CounterBenchmark.prometheusCachedLabelValuesInc 545.13M ± 14680.92K ops/s
CounterBenchmark.prometheusCachedLabelValuesIncSingleThread 334.68M ± 264.93K ops/s
CounterBenchmark.prometheusLabelValuesInc 79.16M ± 2338.51K ops/s
CounterBenchmark.prometheusLabelValuesIncSingleThread 42.41M ± 73.41K ops/s

Allocation per operation

JMH GC profiler gc.alloc.rate.norm, in bytes per benchmark operation (lower is better).
Delta is PR minus base, shown only for matching benchmark configurations. Values are descriptive, not statistical regression verdicts; — means unavailable or not comparable. Each benchmark defines its own operation.

Benchmark PR B/op Base B/op Delta B/op
CounterBenchmark.prometheusAdd 0.071 0.072 -0.001
CounterBenchmark.prometheusCachedLabelValuesInc 0.000
CounterBenchmark.prometheusCachedLabelValuesIncSingleThread 0.000
CounterBenchmark.prometheusInc 0.058 0.055 +0.002
CounterBenchmark.prometheusLabelValuesInc 64.000
CounterBenchmark.prometheusLabelValuesIncSingleThread 64.000
CounterBenchmark.prometheusNoLabelsInc 0.066 0.065 +0.000
HistogramBenchmark.prometheusClassic 0.693 0.697 -0.005
HistogramBenchmark.prometheusClassicPerThread 0.482 0.471 +0.011
HistogramBenchmark.prometheusClassicSingleThread 0.419 0.420 -0.001
HistogramBenchmark.prometheusNative 335792.994 417712.999 -81920.005
HistogramTextFormatBenchmark.openMetricsWriteToNull 43648.193 43648.193 +0.000
HistogramTextFormatBenchmark.prometheusWriteToNull 43648.193 43648.192 +0.001
TextFormatUtilBenchmark.openMetricsWriteToByteArray 19232.002 19232.002 -0.000
TextFormatUtilBenchmark.openMetricsWriteToNull 19232.002 19232.002 +0.000
TextFormatUtilBenchmark.prometheusWriteToByteArray 19256.002 19274.669 -18.667
TextFormatUtilBenchmark.prometheusWriteToNull 19256.002 19256.002 +0.000

Raw Results

Benchmark                                            Mode  Cnt          Score        Error  Units
CounterBenchmark.prometheusAdd                      thrpt   15      51496.390    ± 253.374  ops/s
CounterBenchmark.prometheusCachedLabelValuesInc     thrpt   15  545133195.030 ± 14680920.414  ops/s
CounterBenchmark.prometheusCachedLabelValuesIncSingleThread  thrpt   15  334682040.877 ± 264927.569  ops/s
CounterBenchmark.prometheusInc                      thrpt   15      64080.543   ± 4654.486  ops/s
CounterBenchmark.prometheusLabelValuesInc           thrpt   15   79162116.785 ± 2338513.009  ops/s
CounterBenchmark.prometheusLabelValuesIncSingleThread  thrpt   15   42411525.151  ± 73406.411  ops/s
CounterBenchmark.prometheusNoLabelsInc              thrpt   15      56099.483    ± 833.351  ops/s
HistogramBenchmark.prometheusClassic                thrpt   15       5456.870   ± 1037.588  ops/s
HistogramBenchmark.prometheusClassicPerThread       thrpt   15      17005.455     ± 24.654  ops/s
HistogramBenchmark.prometheusClassicSingleThread    thrpt   15       6949.630     ± 27.499  ops/s
HistogramBenchmark.prometheusNative                 thrpt   15       3784.768    ± 422.259  ops/s
HistogramTextFormatBenchmark.openMetricsWriteToNull  thrpt   15      18124.972     ± 90.417  ops/s
HistogramTextFormatBenchmark.prometheusWriteToNull  thrpt   15      18169.114     ± 83.732  ops/s
TextFormatUtilBenchmark.openMetricsWriteToByteArray  thrpt   15     288209.753   ± 2895.280  ops/s
TextFormatUtilBenchmark.openMetricsWriteToNull      thrpt   15     287946.900   ± 4484.274  ops/s
TextFormatUtilBenchmark.prometheusWriteToByteArray  thrpt   15     307055.686   ± 5488.215  ops/s
TextFormatUtilBenchmark.prometheusWriteToNull       thrpt   15     310087.174   ± 3028.769  ops/s

Notes

  • Score = the JMH primary metric; throughput is higher-is-better and latency is lower-is-better.
  • Error = 99.9% confidence interval
  • Regression verdict requires comparable benchmark metadata, non-overlapping JMH confidence intervals, and a change of at least 5%; otherwise it is marked "within noise" or "inconclusive".
  • Scores for different benchmark methods are not ranked against one another; they may measure different workloads.

Benchmark Descriptions

Benchmark Description
CounterBenchmark Counter updates and label-value lookup (selected methods only)
HistogramBenchmark Histogram observation performance (classic vs native/exponential)
TextFormatUtilBenchmark Metric exposition format writing speed

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
@zeitlinger

Copy link
Copy Markdown
Member Author

I rebased this benchmark PR additively with the focused buffer handoff fix from #2471 so its full CI can validate on the same head. Relevant core regression tests pass locally, lint and mise run build -- -DskipITs=true pass. No benchmark scope changes.

@zeitlinger
zeitlinger enabled auto-merge (squash) September 15, 2026 16:06
zeitlinger added a commit that referenced this pull request Sep 15, 2026
Improve benchmark comparison reporting without changing benchmark
execution or sample configuration.

- Display JMH 99.9% confidence intervals beside PR and base means.
- Distinguish overlapping intervals, below-threshold changes, and
missing/invalid uncertainty.
- Keep the verdict explicitly conservative and heuristic, not a
significance test.
- Add coverage for rendering, malformed data, thresholds, metadata
mismatch, and the supplied overlapping example.

This is separate from #2468 and does not rerun benchmarks.

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
@zeitlinger
zeitlinger disabled auto-merge September 15, 2026 16:35
@zeitlinger
zeitlinger merged commit 59ca1f0 into main Sep 15, 2026
18 of 20 checks passed
@zeitlinger
zeitlinger deleted the bench/pr-client-only-label-lookup branch September 15, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants