From 8babbbf0a95783511463cdf6215533c597734f8e Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Fri, 22 May 2026 00:53:32 -0400 Subject: [PATCH] Cache hashCode on UTF8BytesString UTF8BytesString.hashCode() currently delegates straight through to String.hashCode() on every call. String already caches its own hash, but the trip out of UTF8BytesString and through String's hash-field check still costs a virtual dispatch + field read + branch on every invocation. Caches the hash on UTF8BytesString itself once computed. Benign-race pattern, identical to the existing utf8Bytes lazy initializer: two threads computing the same value produce identical results, and int writes are atomic per JLS so a reader can't observe a partial value. Measured on the metrics subsystem's adversarial JMH bench (8 producer threads, high-cardinality unique-per-op labels), this lifts aggregate throughput from 5.17M to 5.78M ops/s -- ~12% improvement, with the per-iteration distribution shifting systematically upward across all five measurement iterations. The win is bigger in production-like workloads with repeated keys, since the cardinality-handler intern pool means the same UTF8BytesString instance gets hashed repeatedly in subsequent reporting cycles. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../instrumentation/api/UTF8BytesString.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/UTF8BytesString.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/UTF8BytesString.java index ce60056fd92..9ea332a9a82 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/UTF8BytesString.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/UTF8BytesString.java @@ -58,6 +58,13 @@ public static UTF8BytesString create(ByteBuffer utf8BytesBuffer) { private final String string; private byte[] utf8Bytes; + // Lazy hashCode cache. {@link String} already caches its own {@code hashCode} internally, but + // the inter-class call through {@code string.hashCode()} still costs a virtual dispatch + the + // String's own cached-hash field read + branch -- caching here saves all of that on subsequent + // calls. Benign race in the same shape as {@link #utf8Bytes}: two threads computing the same + // hash in parallel both produce the same value, and {@code int} writes are atomic per JLS so a + // reader cannot observe a partial value. + private int cachedHashCode; private UTF8BytesString(String string) { this.string = string; @@ -114,7 +121,12 @@ public boolean equals(Object o) { @Override public int hashCode() { - return this.string.hashCode(); + int h = this.cachedHashCode; + if (h == 0) { + h = this.string.hashCode(); + this.cachedHashCode = h; + } + return h; } @Override