From 01fdfbe11587b536d5a17afa6ea9fa283c059992 Mon Sep 17 00:00:00 2001
From: Jack Berg <34418638+jack-berg@users.noreply.github.com>
Date: Wed, 16 Sep 2026 15:15:11 -0500
Subject: [PATCH 1/2] Update otel benchmark dependencies, add otel bound
instrument scenarios
Signed-off-by: Jack Berg <34418638+jack-berg@users.noreply.github.com>
---
benchmarks/pom.xml | 23 ++++
.../metrics/benchmarks/CounterBenchmark.java | 64 +++++++++++
.../benchmarks/HistogramBenchmark.java | 106 ++++++++++++++++++
3 files changed, 193 insertions(+)
diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml
index 6d8c9c5c45..32170a40cb 100644
--- a/benchmarks/pom.xml
+++ b/benchmarks/pom.xml
@@ -19,12 +19,31 @@
1.37
0.16.0
3.0.2
+
+ 1.66.0
true
true
+
+
+ io.opentelemetry
+ opentelemetry-bom
+ ${benchmark.otel.version}
+ pom
+ import
+
+
+ io.opentelemetry
+ opentelemetry-bom-alpha
+ ${benchmark.otel.version}-alpha
+ pom
+ import
+
io.opentelemetry.instrumentation
opentelemetry-instrumentation-bom-alpha
@@ -73,6 +92,10 @@
io.opentelemetry
opentelemetry-sdk-testing
+
+ io.opentelemetry
+ opentelemetry-api-incubator
+
${project.artifactId}
diff --git a/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/CounterBenchmark.java b/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/CounterBenchmark.java
index d8b75e437c..2b612a7f24 100644
--- a/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/CounterBenchmark.java
+++ b/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/CounterBenchmark.java
@@ -3,10 +3,15 @@
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.incubator.metrics.BoundDoubleCounter;
+import io.opentelemetry.api.incubator.metrics.BoundLongCounter;
+import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounter;
+import io.opentelemetry.api.incubator.metrics.ExtendedLongCounter;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.metrics.ExemplarFilter;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader;
@@ -94,6 +99,7 @@ public OpenTelemetryCounter() {
SdkMeterProvider.builder()
.registerMetricReader(InMemoryMetricReader.create())
.setResource(Resource.getDefault())
+ .setExemplarFilter(ExemplarFilter.alwaysOff())
.build();
OpenTelemetry openTelemetry =
OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
@@ -111,6 +117,45 @@ public OpenTelemetryCounter() {
}
}
+ /**
+ * OpenTelemetry counter using the incubator "bound instrument" API, which pre-binds a set of
+ * attributes at initialization time to avoid a per-record attribute map lookup.
+ */
+ @State(Scope.Benchmark)
+ public static class OpenTelemetryBoundCounter {
+
+ final BoundLongCounter longCounter;
+ final BoundDoubleCounter doubleCounter;
+
+ public OpenTelemetryBoundCounter() {
+
+ SdkMeterProvider sdkMeterProvider =
+ SdkMeterProvider.builder()
+ .registerMetricReader(InMemoryMetricReader.create())
+ .setResource(Resource.getDefault())
+ .setExemplarFilter(ExemplarFilter.alwaysOff())
+ .build();
+ OpenTelemetry openTelemetry =
+ OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
+ Meter meter =
+ openTelemetry
+ .meterBuilder("instrumentation-library-name")
+ .setInstrumentationVersion("1.0.0")
+ .build();
+ Attributes attributes =
+ Attributes.of(
+ AttributeKey.stringKey("path"), "/",
+ AttributeKey.stringKey("status"), "200");
+ this.longCounter =
+ ((ExtendedLongCounter) meter.counterBuilder("test1").setDescription("test").build())
+ .bind(attributes);
+ this.doubleCounter =
+ ((ExtendedDoubleCounter)
+ meter.counterBuilder("test2").ofDoubles().setDescription("test").build())
+ .bind(attributes);
+ }
+ }
+
@Benchmark
@Threads(4)
public CounterDataPoint prometheusAdd(RandomNumbers randomNumbers, PrometheusCounter counter) {
@@ -156,6 +201,25 @@ public LongCounter openTelemetryIncNoLabels(OpenTelemetryCounter counter) {
return counter.longCounter;
}
+ @Benchmark
+ @Threads(4)
+ public BoundDoubleCounter openTelemetryBoundAdd(
+ RandomNumbers randomNumbers, OpenTelemetryBoundCounter counter) {
+ for (int i = 0; i < randomNumbers.randomNumbers.length; i++) {
+ counter.doubleCounter.add(randomNumbers.randomNumbers[i]);
+ }
+ return counter.doubleCounter;
+ }
+
+ @Benchmark
+ @Threads(4)
+ public BoundLongCounter openTelemetryBoundInc(OpenTelemetryBoundCounter counter) {
+ for (int i = 0; i < 10 * 1024; i++) {
+ counter.longCounter.add(1);
+ }
+ return counter.longCounter;
+ }
+
@Benchmark
@Threads(4)
public io.prometheus.client.Counter.Child simpleclientAdd(
diff --git a/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java b/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java
index 41b7097dbc..3878568925 100644
--- a/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java
+++ b/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java
@@ -1,9 +1,14 @@
package io.prometheus.metrics.benchmarks;
import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.incubator.metrics.BoundDoubleHistogram;
+import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.metrics.Aggregation;
+import io.opentelemetry.sdk.metrics.ExemplarFilter;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.View;
@@ -95,6 +100,7 @@ public OpenTelemetryClassicHistogram() {
SdkMeterProvider.builder()
.registerMetricReader(InMemoryMetricReader.create())
.setResource(Resource.getDefault())
+ .setExemplarFilter(ExemplarFilter.alwaysOff())
.registerView(
InstrumentSelector.builder().setName("test").build(),
View.builder()
@@ -126,6 +132,7 @@ public OpenTelemetryExponentialHistogram() {
SdkMeterProvider.builder()
.registerMetricReader(InMemoryMetricReader.create())
.setResource(Resource.getDefault())
+ .setExemplarFilter(ExemplarFilter.alwaysOff())
.registerView(
InstrumentSelector.builder().setName("test").build(),
View.builder()
@@ -143,6 +150,85 @@ public OpenTelemetryExponentialHistogram() {
}
}
+ /**
+ * OpenTelemetry classic histogram using the incubator "bound instrument" API to pre-bind
+ * attributes at initialization time.
+ */
+ @State(Scope.Benchmark)
+ public static class OpenTelemetryBoundClassicHistogram {
+
+ final BoundDoubleHistogram histogram;
+
+ public OpenTelemetryBoundClassicHistogram() {
+ SdkMeterProvider sdkMeterProvider =
+ SdkMeterProvider.builder()
+ .registerMetricReader(InMemoryMetricReader.create())
+ .setResource(Resource.getDefault())
+ .setExemplarFilter(ExemplarFilter.alwaysOff())
+ .registerView(
+ InstrumentSelector.builder().setName("test").build(),
+ View.builder()
+ .setAggregation(
+ Aggregation.explicitBucketHistogram(
+ Arrays.asList(
+ .005, .01, .025, .05, .1, .25, .5, 1.0, 2.5, 5.0, 10.0)))
+ .build())
+ .build();
+ OpenTelemetry openTelemetry =
+ OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
+ Meter meter =
+ openTelemetry
+ .meterBuilder("instrumentation-library-name")
+ .setInstrumentationVersion("1.0.0")
+ .build();
+ Attributes attributes =
+ Attributes.of(
+ AttributeKey.stringKey("path"), "/",
+ AttributeKey.stringKey("status"), "200");
+ this.histogram =
+ ((ExtendedDoubleHistogram) meter.histogramBuilder("test").setDescription("test").build())
+ .bind(attributes);
+ }
+ }
+
+ /**
+ * OpenTelemetry exponential histogram using the incubator "bound instrument" API to pre-bind
+ * attributes at initialization time.
+ */
+ @State(Scope.Benchmark)
+ public static class OpenTelemetryBoundExponentialHistogram {
+
+ final BoundDoubleHistogram histogram;
+
+ public OpenTelemetryBoundExponentialHistogram() {
+ SdkMeterProvider sdkMeterProvider =
+ SdkMeterProvider.builder()
+ .registerMetricReader(InMemoryMetricReader.create())
+ .setResource(Resource.getDefault())
+ .setExemplarFilter(ExemplarFilter.alwaysOff())
+ .registerView(
+ InstrumentSelector.builder().setName("test").build(),
+ View.builder()
+ .setAggregation(Aggregation.base2ExponentialBucketHistogram(10_000, 5))
+ .build())
+ .build();
+ OpenTelemetry openTelemetry =
+ OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
+ Meter meter =
+ openTelemetry
+ .meterBuilder("instrumentation-library-name")
+ .setInstrumentationVersion("1.0.0")
+ .build();
+ Attributes attributes =
+ Attributes.of(
+ AttributeKey.stringKey("path"), "/",
+ AttributeKey.stringKey("status"), "200");
+ this.histogram =
+ ((ExtendedDoubleHistogram) meter.histogramBuilder("test").setDescription("test").build())
+ .bind(attributes);
+ }
+ }
+
@Benchmark
@Threads(4)
public Histogram prometheusClassic(
@@ -212,4 +298,24 @@ public io.opentelemetry.api.metrics.DoubleHistogram openTelemetryExponential(
}
return histogram.histogram;
}
+
+ @Benchmark
+ @Threads(4)
+ public BoundDoubleHistogram openTelemetryBoundClassic(
+ RandomNumbers randomNumbers, OpenTelemetryBoundClassicHistogram histogram) {
+ for (int i = 0; i < randomNumbers.randomNumbers.length; i++) {
+ histogram.histogram.record(randomNumbers.randomNumbers[i]);
+ }
+ return histogram.histogram;
+ }
+
+ @Benchmark
+ @Threads(4)
+ public BoundDoubleHistogram openTelemetryBoundExponential(
+ RandomNumbers randomNumbers, OpenTelemetryBoundExponentialHistogram histogram) {
+ for (int i = 0; i < randomNumbers.randomNumbers.length; i++) {
+ histogram.histogram.record(randomNumbers.randomNumbers[i]);
+ }
+ return histogram.histogram;
+ }
}
From fd2c5d59e2fcfbba95762f621c7d69cea843d984 Mon Sep 17 00:00:00 2001
From: Jack Berg <34418638+jack-berg@users.noreply.github.com>
Date: Thu, 17 Sep 2026 14:44:49 -0500
Subject: [PATCH 2/2] PR feedback
Signed-off-by: Jack Berg <34418638+jack-berg@users.noreply.github.com>
---
.../metrics/benchmarks/HistogramBenchmark.java | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java b/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java
index 3878568925..29f730e6f5 100644
--- a/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java
+++ b/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java
@@ -93,6 +93,7 @@ public SimpleclientHistogram() {
public static class OpenTelemetryClassicHistogram {
final io.opentelemetry.api.metrics.DoubleHistogram histogram;
+ final Attributes attributes;
public OpenTelemetryClassicHistogram() {
@@ -118,6 +119,10 @@ public OpenTelemetryClassicHistogram() {
.setInstrumentationVersion("1.0.0")
.build();
this.histogram = meter.histogramBuilder("test").setDescription("test").build();
+ this.attributes =
+ Attributes.of(
+ AttributeKey.stringKey("path"), "/",
+ AttributeKey.stringKey("status"), "200");
}
}
@@ -125,6 +130,7 @@ public OpenTelemetryClassicHistogram() {
public static class OpenTelemetryExponentialHistogram {
final io.opentelemetry.api.metrics.DoubleHistogram histogram;
+ final Attributes attributes;
public OpenTelemetryExponentialHistogram() {
@@ -147,6 +153,10 @@ public OpenTelemetryExponentialHistogram() {
.setInstrumentationVersion("1.0.0")
.build();
this.histogram = meter.histogramBuilder("test").setDescription("test").build();
+ this.attributes =
+ Attributes.of(
+ AttributeKey.stringKey("path"), "/",
+ AttributeKey.stringKey("status"), "200");
}
}
@@ -284,7 +294,7 @@ public io.prometheus.client.Histogram simpleclient(
public io.opentelemetry.api.metrics.DoubleHistogram openTelemetryClassic(
RandomNumbers randomNumbers, OpenTelemetryClassicHistogram histogram) {
for (int i = 0; i < randomNumbers.randomNumbers.length; i++) {
- histogram.histogram.record(randomNumbers.randomNumbers[i]);
+ histogram.histogram.record(randomNumbers.randomNumbers[i], histogram.attributes);
}
return histogram.histogram;
}
@@ -294,7 +304,7 @@ public io.opentelemetry.api.metrics.DoubleHistogram openTelemetryClassic(
public io.opentelemetry.api.metrics.DoubleHistogram openTelemetryExponential(
RandomNumbers randomNumbers, OpenTelemetryExponentialHistogram histogram) {
for (int i = 0; i < randomNumbers.randomNumbers.length; i++) {
- histogram.histogram.record(randomNumbers.randomNumbers[i]);
+ histogram.histogram.record(randomNumbers.randomNumbers[i], histogram.attributes);
}
return histogram.histogram;
}