From d2be535dac3dcb2d0209a257824a04b25066659e Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Wed, 18 Feb 2026 12:12:13 -0500 Subject: [PATCH 1/3] Creating HashingUtils Adding HashingUtils which is a replacement for the hashing routines of java.util.Objects. HashingUtils is specifically designed to avoid var-args allocation which can lead to lots of allocation if hashCode is hot. To demonstrate the potential impact see HashingBenchmark --- .../datadog/trace/util/HashingBenchmark.java | 135 ++++++++++ .../java/datadog/trace/util/HashingUtils.java | 158 ++++++++++++ .../datadog/trace/util/HashingUtilsTest.java | 243 ++++++++++++++++++ 3 files changed, 536 insertions(+) create mode 100644 internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java create mode 100644 internal-api/src/main/java/datadog/trace/util/HashingUtils.java create mode 100644 internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java diff --git a/internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java b/internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java new file mode 100644 index 00000000000..20d256d3e43 --- /dev/null +++ b/internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java @@ -0,0 +1,135 @@ +package datadog.trace.util; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +/** + * In contrast to java.util.Objects.hash, datadog.util.Objects.hash has overrides for different + * parameter counts that allow most callers to avoid calling the var-arg version. This avoids the + * common situation where the JIT's escape analysis is unable to elide the var-arg array allocation. + * + *

This results in 3-4x throughput, but more importantly no allocation as compared to GiBs / sec + * with var-args. + * MacBook M1 using 8 threads/cores with -prof gc + * + * Benchmark Mode Cnt Score Error Units + * + * HashingBenchmark.hash2 thrpt 6 3365779949.250 ± 270198455.226 ops/s + * HashingBenchmark.hash2:gc.alloc.rate thrpt 6 0.001 ± 0.001 MB/sec + * + * HashingBenchmark.hash2_varargs thrpt 6 1194884232.767 ± 39724408.823 ops/s + * HashingBenchmark.hash2_varargs:gc.alloc.rate thrpt 6 27330.473 ± 909.029 MB/sec + * + * + * HashingBenchmark.hash3 thrpt 6 2314013984.714 ± 181952393.469 ops/s + * HashingBenchmark.hash3:gc.alloc.rate thrpt 6 0.001 ± 0.001 MB/sec + * + * HashingBenchmark.hash3_varags thrpt 6 869246242.250 ± 121680442.505 ops/s + * HashingBenchmark.hash3_varags:gc.alloc.rate thrpt 6 26514.569 ± 3709.819 MB/sec + * + * + * HashingBenchmark.hash4 thrpt 6 1866997193.226 ± 181198915.326 ops/s + * HashingBenchmark.hash4:gc.alloc.rate thrpt 6 0.001 ± 0.001 MB/sec + * + * HashingBenchmark.hash4_varargs thrpt 6 702697142.147 ± 24458612.481 ops/s + * HashingBenchmark.hash4_varargs:gc.alloc.rate thrpt 6 21437.996 ± 748.911 MB/sec + * + * + * HashingBenchmark.hash5 thrpt 6 1803117534.112 ± 242918817.144 ops/s + * HashingBenchmark.hash5:gc.alloc.rate thrpt 6 0.001 ± 0.001 MB/sec + * + * HashingBenchmark.hash5_varargs thrpt 6 579139583.196 ± 29525483.594 ops/s + * HashingBenchmark.hash5_varargs:gc.alloc.rate thrpt 6 22082.357 ± 1125.413 MB/sec + * + */ +@Fork(2) +@Warmup(iterations = 2) +@Measurement(iterations = 3) +@Threads(8) +public class HashingBenchmark { + static T init(Supplier supplier) { + return supplier.get(); + } + + // strings used in hashing are set up ahead of time, so that the only allocation is from var-args + static String[] TEST_STRINGS = + init( + () -> { + ThreadLocalRandom random = ThreadLocalRandom.current(); + + String[] strings = new String[1024]; + for (int i = 0; i < strings.length; ++i) { + strings[i] = Double.toString(random.nextDouble()); + } + return strings; + }); + + static { + Thread updaterThread = + new Thread( + () -> { + ThreadLocalRandom random = ThreadLocalRandom.current(); + + while (!Thread.interrupted()) { + str0 = TEST_STRINGS[random.nextInt(0, TEST_STRINGS.length)]; + str1 = TEST_STRINGS[random.nextInt(0, TEST_STRINGS.length)]; + str2 = TEST_STRINGS[random.nextInt(0, TEST_STRINGS.length)]; + str3 = TEST_STRINGS[random.nextInt(0, TEST_STRINGS.length)]; + str4 = TEST_STRINGS[random.nextInt(0, TEST_STRINGS.length)]; + } + }); + updaterThread.setDaemon(true); + updaterThread.start(); + } + + static String str0; + static String str1; + static String str2; + static String str3; + static String str4; + + @Benchmark + public int hash2() { + return datadog.trace.util.Objects.hash(str0, str1); + } + + @Benchmark + public int hash2_varargs() { + return java.util.Objects.hash(str0, str1); + } + + @Benchmark + public int hash3() { + return datadog.trace.util.Objects.hash(str0, str1, str2); + } + + @Benchmark + public int hash3_varags() { + return java.util.Objects.hash(str0, str1, str2); + } + + @Benchmark + public int hash4() { + return datadog.trace.util.Objects.hash(str0, str1, str2, str3); + } + + @Benchmark + public int hash4_varargs() { + return java.util.Objects.hash(str0, str1, str2, str3); + } + + @Benchmark + public int hash5() { + return datadog.trace.util.Objects.hash(str0, str1, str2, str3, str4); + } + + @Benchmark + public int hash5_varargs() { + return java.util.Objects.hash(str0, str1, str2, str3, str4); + } +} diff --git a/internal-api/src/main/java/datadog/trace/util/HashingUtils.java b/internal-api/src/main/java/datadog/trace/util/HashingUtils.java new file mode 100644 index 00000000000..1522554836a --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/util/HashingUtils.java @@ -0,0 +1,158 @@ +package datadog.trace.util; + +/** + * This class is intended to be a drop-in replacement for the hashing portions of java.util.Objects. + * This class provides more convenience methods for hashing primitives and includes overrides for + * hash that take many argument lengths to avoid var-args allocation. + */ +public final class HashingUtils { + private HashingUtils() {} + + public static final int hashCode(Object obj) { + return obj != null ? obj.hashCode() : 0; + } + + public static final int hash(boolean value) { + return Boolean.hashCode(value); + } + + public static final int hash(char value) { + return Character.hashCode(value); + } + + public static final int hash(byte value) { + return Byte.hashCode(value); + } + + public static final int hash(short value) { + return Short.hashCode(value); + } + + public static final int hash(int value) { + return Integer.hashCode(value); + } + + public static final int hash(long value) { + return Long.hashCode(value); + } + + public static final int hash(float value) { + return Float.hashCode(value); + } + + public static final int hash(double value) { + return Double.hashCode(value); + } + + public static final int hash(Object obj) { + return obj != null ? obj.hashCode() : 0; + } + + public static final int hash(Object obj0, Object obj1) { + return hash(hash(obj0), hash(obj1)); + } + + public static final int hash(int hash0, int hash1) { + return 31 * hash0 + hash1; + } + + public static final int hash(Object obj0, Object obj1, Object obj2) { + return hash(hashCode(obj0), hashCode(obj1), hashCode(obj2)); + } + + public static final int hash(int hash0, int hash1, int hash2) { + // DQH - Micro-optimizing, 31 * 31 will constant fold + // Since there are multiple execution ports for load & store, + // this will make good use of the core. + return 31 * 31 * hash0 + 31 * hash1 + hash2; + } + + public static final int hash(Object obj0, Object obj1, Object obj2, Object obj3) { + return hash(hashCode(obj0), hashCode(obj1), hashCode(obj2), hashCode(obj3)); + } + + public static final int hash(int hash0, int hash1, int hash2, int hash3) { + // DQH - Micro-optimizing, 31 * 31 will constant fold + // Since there are multiple execution ports for load & store, + // this will make good use of the core. + return 31 * 31 * 31 * hash0 + 31 * 31 * hash1 + 31 * hash2 + hash3; + } + + public static final int hash(Object obj0, Object obj1, Object obj2, Object obj3, Object obj4) { + return hash(hashCode(obj0), hashCode(obj1), hashCode(obj2), hashCode(obj3)); + } + + public static final int hash(int hash0, int hash1, int hash2, int hash3, int hash4) { + // DQH - Micro-optimizing, 31 * 31 will constant fold + // Since there are multiple execution ports for load & store, + // this will make good use of the core. + return 31 * 31 * 31 * 31 * hash0 + 31 * 31 * 31 * hash1 + 31 * 31 * hash2 + 31 * hash3 + hash4; + } + + @Deprecated + public static final int hash(int[] hashes) { + int result = 0; + for (int hash : hashes) { + result = addToHash(result, hash); + } + return result; + } + + public static final int addToHash(int hash, int value) { + return 31 * hash + value; + } + + public static final int addToHash(int hash, Object obj) { + return addToHash(hash, hashCode(obj)); + } + + public static final int addToHash(int hash, boolean value) { + return addToHash(hash, Boolean.hashCode(value)); + } + + public static final int addToHash(int hash, char value) { + return addToHash(hash, Character.hashCode(value)); + } + + public static final int addToHash(int hash, byte value) { + return addToHash(hash, Byte.hashCode(value)); + } + + public static final int addToHash(int hash, short value) { + return addToHash(hash, Short.hashCode(value)); + } + + public static final int addToHash(int hash, long value) { + return addToHash(hash, Long.hashCode(value)); + } + + public static final int addToHash(int hash, float value) { + return addToHash(hash, Float.hashCode(value)); + } + + public static final int addToHash(int hash, double value) { + return addToHash(hash, Double.hashCode(value)); + } + + public static final int hash(Iterable objs) { + int result = 0; + for (Object obj : objs) { + result = addToHash(result, obj); + } + return result; + } + + /** + * Calling this var-arg version can result in large amounts of allocation (see HashingBenchmark) + * Rather than calliing this method, add another override of hash that handles a larger number of + * arguments or use calls to addToHash. + */ + @Deprecated + public static final int hash(Object[] objs) { + int result = 0; + for (Object obj : objs) { + result = addToHash(result, obj); + } + return result; + } +} diff --git a/internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java b/internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java new file mode 100644 index 00000000000..23210190026 --- /dev/null +++ b/internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java @@ -0,0 +1,243 @@ +package datadog.trace.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.util.Arrays; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class HashingUtilsTest { + @Test + public void hashCode_() { + assertEquals("bar".hashCode(), Objects.hashCode("bar")); + } + + @Test + public void hashCodeNull() { + assertEquals(0, Objects.hash((Object) null)); + } + + @Test + public void hash1() { + assertEquals("foo".hashCode(), Objects.hashCode("foo")); + } + + @Test + public void hash1Null() { + assertEquals(0, Objects.hashCode(null)); + } + + @Test + public void hash2() { + String str0 = "foo"; + String str1 = "bar"; + + assertNotEquals(0, Objects.hash(str0, str1)); + + String clone0 = clone(str0); + String clone1 = clone(str1); + + assertEquals(Objects.hash(str0, str1), Objects.hash(clone0, clone1)); + } + + @Test + public void hash2Null() { + assertEquals(0, Objects.hash(null, null)); + } + + @Test + public void hash3() { + String str0 = "foo"; + String str2 = "quux"; + String str1 = "bar"; + + assertNotEquals(0, Objects.hash(str0, str1, str2)); + + String clone0 = clone(str0); + String clone1 = clone(str1); + String clone2 = clone(str2); + + assertEquals(Objects.hash(str0, str1, str2), Objects.hash(clone0, clone1, clone2)); + } + + @Test + public void hash3Null() { + assertEquals(0, Objects.hash(null, null, null)); + } + + @Test + public void hash4() { + String str0 = "foo"; + String str1 = "bar"; + String str2 = "quux"; + String str3 = "foobar"; + + assertNotEquals(0, Objects.hash(str0, str1, str2, str3)); + + String clone0 = clone(str0); + String clone1 = clone(str1); + String clone2 = clone(str2); + String clone3 = clone(str3); + + assertEquals( + Objects.hash(str0, str1, str2, str3), Objects.hash(clone0, clone1, clone2, clone3)); + } + + @Test + public void hash4Null() { + assertEquals(0, Objects.hash(null, null, null, null)); + } + + @Test + public void hash5() { + String str0 = "foo"; + String str1 = "bar"; + String str2 = "quux"; + String str3 = "foobar"; + String str4 = "hello"; + + assertNotEquals(0, Objects.hash(str0, str1, str2, str3)); + + String clone0 = clone(str0); + String clone1 = clone(str1); + String clone2 = clone(str2); + String clone3 = clone(str3); + String clone4 = clone(str4); + + assertEquals( + Objects.hash(str0, str1, str2, str3, str4), + Objects.hash(clone0, clone1, clone2, clone3, clone4)); + } + + @Test + public void hash5Null() { + assertEquals(0, Objects.hash(null, null, null, null, null)); + } + + @Test + public void hashArrayAndIterable() { + String str0 = "foo"; + String str1 = "bar"; + String str2 = "quux"; + String str3 = "foobar"; + String str4 = "foobaz"; + String str5 = "hello"; + String str6 = "world"; + + Object[] array = new Object[] {str0, str1, str2, str3, str4, str5, str6}; + + int hashArray = Objects.hash(array); + assertNotEquals(0, hashArray); + + int hashIterable = Objects.hash(Arrays.asList(array)); + assertNotEquals(0, hashIterable); + + assertEquals(hashArray, hashIterable); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void booleans(boolean value) { + assertEquals(Boolean.hashCode(value), Objects.hash(value)); + assertEquals(Boolean.hashCode(value), Objects.addToHash(0, value)); + } + + @ParameterizedTest + @ValueSource(chars = {Character.MIN_VALUE, 'a', 'A', '\0', 'z', 'Z', Character.MAX_VALUE}) + public void chars(char value) { + assertEquals(Character.hashCode(value), Objects.hash(value)); + assertEquals(Character.hashCode(value), Objects.addToHash(0, value)); + } + + @ParameterizedTest + @ValueSource(bytes = {Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE}) + public void bytes(byte value) { + assertEquals(Byte.hashCode(value), Objects.hash(value)); + assertEquals(Byte.hashCode(value), Objects.addToHash(0, value)); + } + + @ParameterizedTest + @ValueSource( + shorts = {Short.MIN_VALUE, Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE, Short.MAX_VALUE}) + public void shorts(short value) { + assertEquals(Short.hashCode(value), Objects.hash(value)); + assertEquals(Short.hashCode(value), Objects.addToHash(0, value)); + } + + @ParameterizedTest + @ValueSource( + ints = { + Integer.MIN_VALUE, + Short.MIN_VALUE, + Byte.MIN_VALUE, + -1, + 0, + 1, + Byte.MAX_VALUE, + Short.MAX_VALUE, + Integer.MAX_VALUE + }) + public void ints(int value) { + assertEquals(Integer.hashCode(value), Objects.hash(value)); + assertEquals(Integer.hashCode(value), Objects.addToHash(0, value)); + } + + @ParameterizedTest + @ValueSource( + longs = { + Long.MIN_VALUE, + Integer.MIN_VALUE, + Short.MIN_VALUE, + Byte.MIN_VALUE, + -1, + 0, + 1, + Byte.MAX_VALUE, + Short.MAX_VALUE, + Integer.MAX_VALUE, + Long.MAX_VALUE + }) + public void longs(long value) { + assertEquals(Long.hashCode(value), Objects.hash(value)); + assertEquals(Long.hashCode(value), Objects.addToHash(0, value)); + } + + @ParameterizedTest + @ValueSource(floats = {Float.MIN_VALUE, -1, 0, 1, 2.71828f, 3.1415f, Float.MAX_VALUE}) + public void floats(float value) { + assertEquals(Float.hashCode(value), Objects.hash(value)); + assertEquals(Float.hashCode(value), Objects.addToHash(0, value)); + } + + @ParameterizedTest + @ValueSource( + doubles = { + Double.MIN_VALUE, + Float.MIN_VALUE, + -1, + 0, + 1, + 2.71828, + 3.1415, + Float.MAX_VALUE, + Double.MAX_VALUE + }) + public void floats(double value) { + assertEquals(Double.hashCode(value), Objects.hash(value)); + assertEquals(Double.hashCode(value), Objects.addToHash(0, value)); + } + + static final String clone(String str) { + return new String(str); + } + + static final String[] deepClone(String[] strings) { + String[] clones = new String[strings.length]; + for (int i = 0; i < strings.length; ++i) { + clones[i] = clone(strings[i]); + } + return clones; + } +} From f6a9728ee0774321563c4fc79418c803a40e5819 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Wed, 18 Feb 2026 14:02:35 -0500 Subject: [PATCH 2/3] Renamed Objects -> HashingUtils --- .../datadog/trace/util/HashingUtilsTest.java | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java b/internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java index 23210190026..185d5a4f2e4 100644 --- a/internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java +++ b/internal-api/src/test/java/datadog/trace/util/HashingUtilsTest.java @@ -11,22 +11,22 @@ public class HashingUtilsTest { @Test public void hashCode_() { - assertEquals("bar".hashCode(), Objects.hashCode("bar")); + assertEquals("bar".hashCode(), HashingUtils.hashCode("bar")); } @Test public void hashCodeNull() { - assertEquals(0, Objects.hash((Object) null)); + assertEquals(0, HashingUtils.hash((Object) null)); } @Test public void hash1() { - assertEquals("foo".hashCode(), Objects.hashCode("foo")); + assertEquals("foo".hashCode(), HashingUtils.hashCode("foo")); } @Test public void hash1Null() { - assertEquals(0, Objects.hashCode(null)); + assertEquals(0, HashingUtils.hashCode(null)); } @Test @@ -34,17 +34,17 @@ public void hash2() { String str0 = "foo"; String str1 = "bar"; - assertNotEquals(0, Objects.hash(str0, str1)); + assertNotEquals(0, HashingUtils.hash(str0, str1)); String clone0 = clone(str0); String clone1 = clone(str1); - assertEquals(Objects.hash(str0, str1), Objects.hash(clone0, clone1)); + assertEquals(HashingUtils.hash(str0, str1), HashingUtils.hash(clone0, clone1)); } @Test public void hash2Null() { - assertEquals(0, Objects.hash(null, null)); + assertEquals(0, HashingUtils.hash(null, null)); } @Test @@ -53,18 +53,18 @@ public void hash3() { String str2 = "quux"; String str1 = "bar"; - assertNotEquals(0, Objects.hash(str0, str1, str2)); + assertNotEquals(0, HashingUtils.hash(str0, str1, str2)); String clone0 = clone(str0); String clone1 = clone(str1); String clone2 = clone(str2); - assertEquals(Objects.hash(str0, str1, str2), Objects.hash(clone0, clone1, clone2)); + assertEquals(HashingUtils.hash(str0, str1, str2), HashingUtils.hash(clone0, clone1, clone2)); } @Test public void hash3Null() { - assertEquals(0, Objects.hash(null, null, null)); + assertEquals(0, HashingUtils.hash(null, null, null)); } @Test @@ -74,7 +74,7 @@ public void hash4() { String str2 = "quux"; String str3 = "foobar"; - assertNotEquals(0, Objects.hash(str0, str1, str2, str3)); + assertNotEquals(0, HashingUtils.hash(str0, str1, str2, str3)); String clone0 = clone(str0); String clone1 = clone(str1); @@ -82,12 +82,13 @@ public void hash4() { String clone3 = clone(str3); assertEquals( - Objects.hash(str0, str1, str2, str3), Objects.hash(clone0, clone1, clone2, clone3)); + HashingUtils.hash(str0, str1, str2, str3), + HashingUtils.hash(clone0, clone1, clone2, clone3)); } @Test public void hash4Null() { - assertEquals(0, Objects.hash(null, null, null, null)); + assertEquals(0, HashingUtils.hash(null, null, null, null)); } @Test @@ -98,7 +99,7 @@ public void hash5() { String str3 = "foobar"; String str4 = "hello"; - assertNotEquals(0, Objects.hash(str0, str1, str2, str3)); + assertNotEquals(0, HashingUtils.hash(str0, str1, str2, str3)); String clone0 = clone(str0); String clone1 = clone(str1); @@ -107,13 +108,13 @@ public void hash5() { String clone4 = clone(str4); assertEquals( - Objects.hash(str0, str1, str2, str3, str4), - Objects.hash(clone0, clone1, clone2, clone3, clone4)); + HashingUtils.hash(str0, str1, str2, str3, str4), + HashingUtils.hash(clone0, clone1, clone2, clone3, clone4)); } @Test public void hash5Null() { - assertEquals(0, Objects.hash(null, null, null, null, null)); + assertEquals(0, HashingUtils.hash(null, null, null, null, null)); } @Test @@ -128,10 +129,10 @@ public void hashArrayAndIterable() { Object[] array = new Object[] {str0, str1, str2, str3, str4, str5, str6}; - int hashArray = Objects.hash(array); + int hashArray = HashingUtils.hash(array); assertNotEquals(0, hashArray); - int hashIterable = Objects.hash(Arrays.asList(array)); + int hashIterable = HashingUtils.hash(Arrays.asList(array)); assertNotEquals(0, hashIterable); assertEquals(hashArray, hashIterable); @@ -140,30 +141,30 @@ public void hashArrayAndIterable() { @ParameterizedTest @ValueSource(booleans = {false, true}) public void booleans(boolean value) { - assertEquals(Boolean.hashCode(value), Objects.hash(value)); - assertEquals(Boolean.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Boolean.hashCode(value), HashingUtils.hash(value)); + assertEquals(Boolean.hashCode(value), HashingUtils.addToHash(0, value)); } @ParameterizedTest @ValueSource(chars = {Character.MIN_VALUE, 'a', 'A', '\0', 'z', 'Z', Character.MAX_VALUE}) public void chars(char value) { - assertEquals(Character.hashCode(value), Objects.hash(value)); - assertEquals(Character.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Character.hashCode(value), HashingUtils.hash(value)); + assertEquals(Character.hashCode(value), HashingUtils.addToHash(0, value)); } @ParameterizedTest @ValueSource(bytes = {Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE}) public void bytes(byte value) { - assertEquals(Byte.hashCode(value), Objects.hash(value)); - assertEquals(Byte.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Byte.hashCode(value), HashingUtils.hash(value)); + assertEquals(Byte.hashCode(value), HashingUtils.addToHash(0, value)); } @ParameterizedTest @ValueSource( shorts = {Short.MIN_VALUE, Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE, Short.MAX_VALUE}) public void shorts(short value) { - assertEquals(Short.hashCode(value), Objects.hash(value)); - assertEquals(Short.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Short.hashCode(value), HashingUtils.hash(value)); + assertEquals(Short.hashCode(value), HashingUtils.addToHash(0, value)); } @ParameterizedTest @@ -180,8 +181,8 @@ public void shorts(short value) { Integer.MAX_VALUE }) public void ints(int value) { - assertEquals(Integer.hashCode(value), Objects.hash(value)); - assertEquals(Integer.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Integer.hashCode(value), HashingUtils.hash(value)); + assertEquals(Integer.hashCode(value), HashingUtils.addToHash(0, value)); } @ParameterizedTest @@ -200,15 +201,15 @@ public void ints(int value) { Long.MAX_VALUE }) public void longs(long value) { - assertEquals(Long.hashCode(value), Objects.hash(value)); - assertEquals(Long.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Long.hashCode(value), HashingUtils.hash(value)); + assertEquals(Long.hashCode(value), HashingUtils.addToHash(0, value)); } @ParameterizedTest @ValueSource(floats = {Float.MIN_VALUE, -1, 0, 1, 2.71828f, 3.1415f, Float.MAX_VALUE}) public void floats(float value) { - assertEquals(Float.hashCode(value), Objects.hash(value)); - assertEquals(Float.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Float.hashCode(value), HashingUtils.hash(value)); + assertEquals(Float.hashCode(value), HashingUtils.addToHash(0, value)); } @ParameterizedTest @@ -225,8 +226,8 @@ public void floats(float value) { Double.MAX_VALUE }) public void floats(double value) { - assertEquals(Double.hashCode(value), Objects.hash(value)); - assertEquals(Double.hashCode(value), Objects.addToHash(0, value)); + assertEquals(Double.hashCode(value), HashingUtils.hash(value)); + assertEquals(Double.hashCode(value), HashingUtils.addToHash(0, value)); } static final String clone(String str) { From 4f7064fd8eeb4ee83c5dc253399bafeeac9191b1 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Wed, 18 Feb 2026 15:37:04 -0500 Subject: [PATCH 3/3] Fix-up after renaming --- .../jmh/java/datadog/trace/util/HashingBenchmark.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java b/internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java index 20d256d3e43..93a3d93e5f6 100644 --- a/internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java +++ b/internal-api/src/jmh/java/datadog/trace/util/HashingBenchmark.java @@ -9,7 +9,7 @@ import org.openjdk.jmh.annotations.Warmup; /** - * In contrast to java.util.Objects.hash, datadog.util.Objects.hash has overrides for different + * In contrast to java.util.Objects.hash, datadog.util.HashingUtils.hash has overrides for different * parameter counts that allow most callers to avoid calling the var-arg version. This avoids the * common situation where the JIT's escape analysis is unable to elide the var-arg array allocation. * @@ -95,7 +95,7 @@ static T init(Supplier supplier) { @Benchmark public int hash2() { - return datadog.trace.util.Objects.hash(str0, str1); + return datadog.trace.util.HashingUtils.hash(str0, str1); } @Benchmark @@ -105,7 +105,7 @@ public int hash2_varargs() { @Benchmark public int hash3() { - return datadog.trace.util.Objects.hash(str0, str1, str2); + return datadog.trace.util.HashingUtils.hash(str0, str1, str2); } @Benchmark @@ -115,7 +115,7 @@ public int hash3_varags() { @Benchmark public int hash4() { - return datadog.trace.util.Objects.hash(str0, str1, str2, str3); + return datadog.trace.util.HashingUtils.hash(str0, str1, str2, str3); } @Benchmark @@ -125,7 +125,7 @@ public int hash4_varargs() { @Benchmark public int hash5() { - return datadog.trace.util.Objects.hash(str0, str1, str2, str3, str4); + return datadog.trace.util.HashingUtils.hash(str0, str1, str2, str3, str4); } @Benchmark