From c07c5aa8b3d32b952d69ed6433494320104ab9d6 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 16 Mar 2023 15:18:11 -0500 Subject: [PATCH] Cache ImmutableKeyValuePairs#hashCode --- .../api/common/AttributesBenchmark.java | 19 +++++++++++++ .../api/internal/ImmutableKeyValuePairs.java | 11 +++++--- .../sdk/metrics/MetricsBenchmarks.java | 27 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/api/all/src/jmh/java/io/opentelemetry/api/common/AttributesBenchmark.java b/api/all/src/jmh/java/io/opentelemetry/api/common/AttributesBenchmark.java index e0c7de41bf5..8b3d16425fc 100644 --- a/api/all/src/jmh/java/io/opentelemetry/api/common/AttributesBenchmark.java +++ b/api/all/src/jmh/java/io/opentelemetry/api/common/AttributesBenchmark.java @@ -25,11 +25,30 @@ public class AttributesBenchmark { // pre-allocate the keys & values to remove one possible confounding factor private static final List> keys = new ArrayList<>(10); private static final List values = new ArrayList<>(10); + private static final List attributes = new ArrayList<>(); static { for (int i = 0; i < 10; i++) { keys.add(AttributeKey.stringKey("key" + i)); values.add("value" + i); + AttributesBuilder builder = Attributes.builder(); + for (int j = 0; j <= i; j++) { + builder.put(keys.get(j), values.get(j)); + } + attributes.add(builder.build()); + } + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @Fork(1) + @Measurement(iterations = 15, time = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 5, time = 1) + @SuppressWarnings("ReturnValueIgnored") + public void computeHashCode() { + for (Attributes attributes : attributes) { + attributes.hashCode(); } } diff --git a/api/all/src/main/java/io/opentelemetry/api/internal/ImmutableKeyValuePairs.java b/api/all/src/main/java/io/opentelemetry/api/internal/ImmutableKeyValuePairs.java index 270b9bd4f9c..a2590633b83 100644 --- a/api/all/src/main/java/io/opentelemetry/api/internal/ImmutableKeyValuePairs.java +++ b/api/all/src/main/java/io/opentelemetry/api/internal/ImmutableKeyValuePairs.java @@ -32,6 +32,7 @@ @Immutable public abstract class ImmutableKeyValuePairs { private final Object[] data; + private int hashcode; /** * Stores the raw object data directly. Does not do any de-duping or sorting. If you use this @@ -247,9 +248,13 @@ public boolean equals(@Nullable Object o) { @Override public int hashCode() { - int result = 1; - result *= 1000003; - result ^= Arrays.hashCode(data); + int result = hashcode; + if (result == 0) { + result = 1; + result *= 1000003; + result ^= Arrays.hashCode(data); + hashcode = result; + } return result; } diff --git a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/MetricsBenchmarks.java b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/MetricsBenchmarks.java index aaf11a16be5..a77c3200d28 100644 --- a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/MetricsBenchmarks.java +++ b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/MetricsBenchmarks.java @@ -6,9 +6,12 @@ package io.opentelemetry.sdk.metrics; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -32,6 +35,22 @@ @Fork(1) public class MetricsBenchmarks { + private static final List ATTRIBUTES_LIST; + + static { + int keys = 5; + int valuesPerKey = 20; + + ATTRIBUTES_LIST = new ArrayList<>(); + for (int key = 0; key < keys; key++) { + AttributesBuilder builder = Attributes.builder(); + for (int value = 0; value < valuesPerKey; value++) { + builder.put("key_" + key, "value_" + value); + } + ATTRIBUTES_LIST.add(builder.build()); + } + } + @State(Scope.Thread) public static class ThreadState { @@ -65,6 +84,14 @@ public void tearDown(ThreadParams threadParams) { } } + @Benchmark + @Threads(1) + public void recordToMultipleAttributes(ThreadState threadState) { + for (Attributes attributes : ATTRIBUTES_LIST) { + threadState.op.perform(attributes); + } + } + @Benchmark @Threads(1) public void oneThread(ThreadState threadState) {