From b9370e61d267992aa24b381f1bd3b18c84ce5122 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Sat, 17 Oct 2026 18:17:00 +0100 Subject: [PATCH] Simplifies InternalNames with linear probing and cached hashes Replaces bounded rehashing and repeated table growth with a fixed table sized to at most 50% load. Resolves collisions by linear probing and keeps hashes in a parallel array to avoid accessing strings whose hashes differ. Collisions, wraparound, normalized duplicates, and allocation-free CharSequence lookups are checked in InternalNamesTest. Moves the class-name corpus into testing and exposes it through SampleClasses.loadClassNames(). Updates the utils benchmarks to use the shared resource, and adds an InternalNames benchmark matching all 33,957 corpus names against 25 groups sampled from dd-trace-java, using both String and TypeString queries. The benchmark checks every corpus class against every sampled group and reports time per class. It normalizes names and precompute hashes outside measurement, validates membership against HashSet during setup, and returns the total match count to keep all lookups observable. --- .../classmatch/InternalNamesBenchmark.java | 122 ++++++++++ .../classmatch/type-name-groups.csv | 27 +++ .../instrument/classmatch/InternalNames.java | 87 +++---- .../classmatch/InternalNamesTest.java | 214 ++++++++++++++++++ .../instrument/testing/SampleClasses.java | 30 ++- .../testing}/sample_class_names.txt | 0 .../utils/ClassInfoCacheBenchmark.java | 11 +- .../utils/ClassNameFilterBenchmark.java | 11 +- .../utils/ClassNameTrieBenchmark.java | 11 +- 9 files changed, 428 insertions(+), 85 deletions(-) create mode 100644 class-match/src/jmh/java/datadog/instrument/classmatch/InternalNamesBenchmark.java create mode 100644 class-match/src/jmh/resources/datadog/instrument/classmatch/type-name-groups.csv create mode 100644 class-match/src/test/java/datadog/instrument/classmatch/InternalNamesTest.java rename {utils/src/test/resources => testing/src/main/resources/datadog/instrument/testing}/sample_class_names.txt (100%) diff --git a/class-match/src/jmh/java/datadog/instrument/classmatch/InternalNamesBenchmark.java b/class-match/src/jmh/java/datadog/instrument/classmatch/InternalNamesBenchmark.java new file mode 100644 index 0000000..32003a2 --- /dev/null +++ b/class-match/src/jmh/java/datadog/instrument/classmatch/InternalNamesBenchmark.java @@ -0,0 +1,122 @@ +package datadog.instrument.classmatch; + +import static datadog.instrument.classmatch.InternalMatchers.internalName; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Objects.requireNonNull; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static org.openjdk.jmh.annotations.Mode.AverageTime; + +import datadog.instrument.testing.SampleClasses; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +/** Reports time per corpus class matched against every sampled group, without short-circuiting. */ +@State(Scope.Thread) +@BenchmarkMode(AverageTime) +@OutputTimeUnit(NANOSECONDS) +@Fork(3) +@Warmup(iterations = 4, time = 1) +@Measurement(iterations = 6, time = 1) +public class InternalNamesBenchmark { + private static final int CLASS_COUNT = 33957; + + @Param({"STRING", "TYPE_STRING"}) + public String queryType; + + private InternalNames[] groups; + private CharSequence[] queries; + + @Setup + public void setup() throws IOException { + String[] classNames = + SampleClasses.loadClassNames().stream() + .map(InternalMatchers::internalName) + .toArray(String[]::new); + queries = Arrays.stream(classNames).map(this::query).toArray(CharSequence[]::new); + // OperationsPerInvocation must match the shared corpus size. + if (queries.length != CLASS_COUNT) { + throw new IllegalStateException("Update CLASS_COUNT for the shared corpus"); + } + + List sets = new ArrayList<>(); + long matches = 0; + try (InputStream in = + requireNonNull( + InternalNamesBenchmark.class.getResourceAsStream("type-name-groups.csv"), + "type-name-groups.csv"); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, UTF_8))) { + for (String line; (line = reader.readLine()) != null; ) { + if (line.isEmpty() || line.startsWith("#")) { + continue; + } + String[] columns = line.split(","); + InternalNames names = new InternalNames(Arrays.asList(columns).subList(1, columns.length)); + sets.add(names); + Set expected = new HashSet<>(); + for (int i = 1; i < columns.length; i++) { + expected.add(internalName(columns[i])); + } + // Validate hits even for group members absent from the shared corpus. + for (String name : expected) { + if (!names.containsType(query(name))) { + throw new IllegalStateException("Missing group member: " + name); + } + } + for (int i = 0; i < queries.length; i++) { + CharSequence query = queries[i]; + boolean hit = expected.contains(classNames[i]); + if (names.containsType(query) != hit) { + throw new IllegalStateException("Incorrect corpus membership: " + query); + } + matches += hit ? 1 : 0; + } + } + } + if (sets.isEmpty()) { + throw new IllegalStateException("No sampled groups"); + } + groups = sets.toArray(new InternalNames[0]); + System.out.printf( + "Corpus: %d classes, %d groups, %d hits%n", queries.length, groups.length, matches); + } + + private CharSequence query(String name) { + // Both query forms have their hashes computed outside measurement. + int hash = name.hashCode(); + if (queryType.equals("STRING")) { + return name; + } + String descriptor = "L" + name + ";"; + return new TypeString(descriptor, 1, descriptor.length() - 1, hash); + } + + @Benchmark + @OperationsPerInvocation(CLASS_COUNT) + public long matchAllGroups() { + long matches = 0; + for (CharSequence query : queries) { + for (InternalNames names : groups) { + matches += names.containsType(query) ? 1 : 0; + } + } + return matches; + } +} diff --git a/class-match/src/jmh/resources/datadog/instrument/classmatch/type-name-groups.csv b/class-match/src/jmh/resources/datadog/instrument/classmatch/type-name-groups.csv new file mode 100644 index 0000000..9a79aed --- /dev/null +++ b/class-match/src/jmh/resources/datadog/instrument/classmatch/type-name-groups.csv @@ -0,0 +1,27 @@ +# Literal dotted namedOneOf/namedNoneOf groups of two or more names from dd-trace-java. +# Computed arguments excluded; duplicate groups and argument order retained. +namedOneOf,scala.collection.Seq,scala.collection.immutable.Seq +namedOneOf,software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage,software.amazon.awssdk.core.internal.http.pipeline.stages.MakeAsyncHttpRequestStage +namedOneOf,com.hazelcast.client.impl.HazelcastClientInstanceImpl,com.hazelcast.client.impl.clientside.HazelcastClientInstanceImpl +namedOneOf,org.hibernate.Session,org.hibernate.StatelessSession +namedOneOf,org.hibernate.Session,org.hibernate.StatelessSession +namedOneOf,org.hibernate.Session,org.hibernate.StatelessSession +namedOneOf,com.netflix.hystrix.HystrixCommand,com.netflix.hystrix.HystrixObservableCommand +namedOneOf,org.apache.ignite.cache.query.Query,org.apache.ignite.cache.query.SqlFieldsQuery +namedOneOf,io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe,io.grpc.netty.shaded.io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe,io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe,io.grpc.netty.shaded.io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe,io.netty.channel.kqueue.AbstractKQueueChannel$AbstractKQueueUnsafe,io.grpc.netty.shaded.io.netty.channel.kqueue.AbstractKQueueChannel$AbstractKQueueUnsafe +namedOneOf,reactor.core.scheduler.SchedulerTask,reactor.core.scheduler.WorkerTask +namedOneOf,io.netty.util.concurrent.GlobalEventExecutor,io.grpc.netty.shaded.io.netty.util.concurrent.GlobalEventExecutor,com.couchbase.client.deps.io.netty.util.concurrent.GlobalEventExecutor +namedOneOf,io.netty.handler.timeout.IdleStateHandler,io.grpc.netty.shaded.io.netty.handler.timeout.IdleStateHandler +namedOneOf,io.netty.channel.ChannelHandlerContext,io.grpc.netty.shaded.io.netty.channel.ChannelHandlerContext +namedOneOf,org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor,org.opensearch.common.util.concurrent.OpenSearchThreadPoolExecutor +namedNoneOf,java.lang.ClassLoader,com.ibm.oti.vm.BootstrapClassLoader +namedOneOf,org.eclipse.jetty.client.api.Request,org.eclipse.jetty.client.HttpRequest +namedOneOf,org.eclipse.jetty.client.api.Request,org.eclipse.jetty.client.HttpRequest +namedOneOf,io.micronaut.http.MutableHttpResponse,io.micronaut.http.HttpResponse +namedOneOf,reactor.core.publisher.Mono,reactor.core.publisher.Flux +namedOneOf,reactor.core.publisher.Mono,reactor.core.publisher.Flux +namedOneOf,redis.Request,redis.ActorRequest,redis.BufferedRequest,redis.RoundRobinPoolRequest +namedOneOf,com.ibm.ws.session.HttpSessionFacade,org.apache.catalina.session.StandardSessionFacade +namedOneOf,com.twilio.base.Creator,com.twilio.base.Deleter,com.twilio.base.Fetcher,com.twilio.base.Reader,com.twilio.base.Updater +namedOneOf,com.twilio.base.Creator,com.twilio.base.Deleter,com.twilio.base.Fetcher,com.twilio.base.Reader,com.twilio.base.Updater +namedOneOf,io.vertx.redis.client.impl.RedisConnectionImpl,io.vertx.redis.client.impl.RedisStandaloneConnection diff --git a/class-match/src/main/java/datadog/instrument/classmatch/InternalNames.java b/class-match/src/main/java/datadog/instrument/classmatch/InternalNames.java index a26ad9f..ed5b177 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/InternalNames.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/InternalNames.java @@ -14,16 +14,15 @@ import java.util.NoSuchElementException; /** - * Compact immutable hashtable of internal names, representing types to be matched against. + * Immutable set of internal names using linear probing. A parallel array of cached hashes lets + * probes skip strings whose hashes differ. * - *

The key feature of this implementation is that it supports querying by arbitrary {@link - * CharSequence}s, as long as the char sequence uses the same hash algorithm as {@link String}. + *

Queries may be any {@link CharSequence} with a {@link String}-compatible hash code. */ final class InternalNames extends AbstractSet { - private static final int MAX_HASH_ATTEMPTS = 3; - - private final String[] table; private final int slotMask; + private final int[] hashes; + private final String[] table; /** * Creates a new set of internal names containing the given types of interest. @@ -31,22 +30,25 @@ final class InternalNames extends AbstractSet { * @param types the types of interest */ InternalNames(Collection types) { - // attempt to hash types into a table with ~75% load factor - int tableSize = Math.max(8, types.size() * 4 / 3) - 1; - int slotMask = -1 >>> Integer.numberOfLeadingZeros(tableSize); - String[] table = new String[slotMask + 1]; - Iterator itr = types.iterator(); - while (itr.hasNext()) { - // add types one by one, watching out for unsolvable collisions - if (!add(table, slotMask, internalName(itr.next()))) { - // cannot add type without collision; grow table and restart additions - slotMask = (slotMask << 1) + 1; - table = new String[slotMask + 1]; - itr = types.iterator(); + // At most 50% full, leaving empty slots to terminate probes. + int tableSize = Math.max(8, types.size() * 2) - 1; + + this.slotMask = -1 >>> Integer.numberOfLeadingZeros(tableSize); + this.hashes = new int[slotMask + 1]; + this.table = new String[slotMask + 1]; + + for (String type : types) { + final String name = internalName(type); + final int h = hash(name.hashCode()); + + int hashed, slot = h & slotMask; + while ((hashed = hashes[slot]) != 0 && (hashed != h || !table[slot].equals(name))) { + slot = (slot + 1) & slotMask; } + + hashes[slot] = h; + table[slot] = name; } - this.table = table; - this.slotMask = slotMask; } /** @@ -56,47 +58,24 @@ final class InternalNames extends AbstractSet { * @return {@code true} if the set contains this type; otherwise {@code false} */ public boolean containsType(CharSequence internalName) { - final String[] table = this.table; + final int h = hash(internalName.hashCode()); + final int slotMask = this.slotMask; - for (int i = 1, h = internalName.hashCode(); true; i++, h = rehash(h)) { - String existing = table[slotMask & h]; - if (existing != null) { - // use content-equality, not object-equality - if (existing.contentEquals(internalName)) { - return true; - } else if (i < MAX_HASH_ATTEMPTS) { - continue; // rehash and try again - } - } - return false; - } - } + final int[] hashes = this.hashes; + final String[] table = this.table; - /** - * Attempts to add a type to a hashtable of names, with a bounded amount of rehashing. - * - * @param table a hashtable of internal names - * @param slotMask mask used to map hashes to slots - * @param internalName the internal name of the type - * @return {@code true} if the type was successfully added; otherwise {@code false} - */ - private static boolean add(String[] table, int slotMask, String internalName) { - for (int i = 1, h = internalName.hashCode(); true; i++, h = rehash(h)) { - int slot = slotMask & h; - String existing = table[slot]; - // be prepared to de-duplicate names - if (existing == null || existing.equals(internalName)) { - table[slot] = internalName; + int hashed, slot = h & slotMask; + while ((hashed = hashes[slot]) != 0) { + if (hashed == h && table[slot].contentEquals(internalName)) { return true; - } else if (i < MAX_HASH_ATTEMPTS) { - continue; // rehash and try again } - return false; + slot = (slot + 1) & slotMask; } + return false; } - private static int rehash(int oldHash) { - return Integer.reverseBytes(oldHash * 0x9e3775cd) * 0x9e3775cd; + private static int hash(int h) { + return h != 0 ? h : 0xDD06; // reserve 0 for "no hash" } // ---------------------------------------------------------------------------------------------- diff --git a/class-match/src/test/java/datadog/instrument/classmatch/InternalNamesTest.java b/class-match/src/test/java/datadog/instrument/classmatch/InternalNamesTest.java new file mode 100644 index 0000000..28e1c82 --- /dev/null +++ b/class-match/src/test/java/datadog/instrument/classmatch/InternalNamesTest.java @@ -0,0 +1,214 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2025-Present Datadog, Inc. + */ + +package datadog.instrument.classmatch; + +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.function.Predicate; +import org.junit.jupiter.api.Test; + +class InternalNamesTest { + private static final List COLLISIONS = + asList("pkg.AaAa", "pkg.AaBB", "pkg.BBAa", "pkg.BBBB"); + + @Test + void empty() { + InternalNames names = new InternalNames(Collections.emptyList()); + assertEquals(0, names.size()); + assertFalse(names.containsType("")); + assertFalse(names.iterator().hasNext()); + assertThrows(NoSuchElementException.class, () -> names.iterator().next()); + } + + @Test + void normalNames() { + checkNames( + asList("java.lang.String", "java/lang/String", "pkg.Type", "pkg.Type$Nested", "例.型", "")); + } + + @Test + void largeSet() { + List types = new ArrayList<>(); + for (int i = 0; i < 512; i++) { + types.add("pkg.Type" + i); + } + checkNames(types); + } + + @Test + void collidingNamesFormProbeRun() { + // The first four names collide in a 16-slot table. + InternalNames names = + checkNames(asList("pkg.Type0", "pkg.Type17", "pkg.Type28", "pkg.Type39", "例.型", "")); + // These misses start at the same slot as the colliding names. + assertMissing(names, "pkg/Type110", "pkg/Type121"); + } + + @Test + void neighbouringProbeRunsMerge() { + // Names starting in adjacent slots form a shared probe run. + InternalNames names = + checkNames(asList("pkg.Type0", "pkg.Type1", "pkg.Type17", "pkg.Type18", "例.型", "")); + // The miss must probe past names from both starting slots. + assertMissing(names, "pkg/Type29"); + } + + @Test + void probeRunWrapsAround() { + // Collisions at slot 15 wrap around a 16-slot table. + InternalNames names = + checkNames(asList("pkg.Type13", "pkg.Type24", "pkg.Type35", "pkg.Type14", "", "例.型")); + // Misses must cross the end of the table too. + assertMissing(names, "pkg/Type46", "pkg/Type25"); + } + + @Test + void deduplicatesNormalizedNames() { + checkNames( + asList( + "pkg/AaAa", + "pkg.AaAa", + "pkg.AaBB", + "pkg.BBAa", + "pkg.BBBB", + "pkg.AaAa", + "pkg.AaBB", + "pkg.BBAa", + "pkg.BBBB", + "pkg/AaAa", + "pkg.Type", + "pkg.Type$Nested", + "例.型", + "")); + } + + @Test + void probeRunComparesPrefixesAndUnicode() { + // Short names and Unicode characters share probe runs. + InternalNames names = checkNames(asList("", "h", "hh", "hhh", "p", "\u0100")); + assertMissing(names, "hhhh", "x", "\u0100h", "\ufff8"); + } + + @Test + void manyIdenticalHashesAndMissingNames() { + List types = new ArrayList<>(); + for (int i = 0; i < 256; i += 2) { + types.add(collidingName(i)); + } + InternalNames names = checkNames(types); + for (int i = 0; i < 256; i++) { + String name = collidingName(i); + assertEquals(i % 2 == 0, names.containsType(query(name))); + } + } + + @Test + void matcherFactoriesSupportCollisions() { + TypeMatcher matcher = TypeMatcher.typeOneOf(COLLISIONS); + for (String type : COLLISIONS) { + assertTrue(matcher.test(query(InternalMatchers.internalName(type)))); + } + assertFalse(matcher.test(query("pkg/AaAaAa"))); + Predicate annotations = InternalMatchers.declaresAnnotationOneOf(COLLISIONS); + assertTrue(annotations.test(new String[] {"pkg/Unknown", "pkg/BBBB"})); + assertFalse(annotations.test(new String[] {"pkg/Unknown"})); + } + + @Test + void setContract() { + InternalNames names = new InternalNames(asList("pkg.Type", "pkg.Other")); + Iterator iterator = names.iterator(); + Set actual = new HashSet<>(); + while (iterator.hasNext()) { + assertTrue(iterator.hasNext()); + assertTrue(actual.add(iterator.next())); + } + assertEquals(new HashSet<>(asList("pkg/Type", "pkg/Other")), actual); + assertThrows(UnsupportedOperationException.class, iterator::remove); + assertThrows(NoSuchElementException.class, iterator::next); + assertFalse(names.contains(null)); + assertFalse(names.contains(123)); + } + + private static InternalNames checkNames(List types) { + InternalNames names = new InternalNames(types); + Set expected = new HashSet<>(); + for (String type : types) { + String name = InternalMatchers.internalName(type); + expected.add(name); + assertTrue(names.containsType(name), name); + assertTrue(names.contains(query(name)), name); + assertTrue(names.containsType(typeString(name)), name); + } + assertEquals(expected.size(), names.size()); + assertEquals(expected, new HashSet<>(names)); + assertMissing(names, "!", "pkg/", "pkg/Type$", "pkg/Type$NestedExtra", "例/型別", "\uffff"); + return names; + } + + private static void assertMissing(InternalNames names, String... missing) { + for (String name : missing) { + assertFalse(names.containsType(name), name); + assertFalse(names.containsType(query(name)), name); + assertFalse(names.containsType(typeString(name)), name); + } + } + + private static String collidingName(int bits) { + StringBuilder name = new StringBuilder("pkg/"); + for (int i = 0; i < 8; i++) { + name.append((bits & (1 << i)) == 0 ? "Aa" : "BB"); + } + return name.toString(); + } + + private static TypeString typeString(String name) { + String descriptor = "L" + name + ";"; + return new TypeString(descriptor, 1, descriptor.length() - 1, name.hashCode()); + } + + /** String-compatible hash, identity equality, and no conversion to String allowed. */ + private static CharSequence query(String value) { + return new CharSequence() { + @Override + public int length() { + return value.length(); + } + + @Override + public char charAt(int index) { + return value.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public String toString() { + throw new AssertionError("Lookup must not allocate a String"); + } + }; + } +} diff --git a/testing/src/main/java/datadog/instrument/testing/SampleClasses.java b/testing/src/main/java/datadog/instrument/testing/SampleClasses.java index 07c81d4..4dbd4c6 100644 --- a/testing/src/main/java/datadog/instrument/testing/SampleClasses.java +++ b/testing/src/main/java/datadog/instrument/testing/SampleClasses.java @@ -6,10 +6,15 @@ package datadog.instrument.testing; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Objects.requireNonNull; + +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.util.List; import java.util.Objects; @@ -17,12 +22,29 @@ import java.util.stream.Collectors; /** - * Provides access to external bytecode declared using the {@code sampleBytecode} gradle dependency. + * Sample class names, plus bytecode declared using the {@code sampleBytecode} gradle dependency. */ public final class SampleClasses { /** The directory containing the sample bytecode jars. */ - public static final String SAMPLE_BYTECODE_DIRECTORY = "build/sampleBytecode/"; + private static final String SAMPLE_BYTECODE_DIRECTORY = "build/sampleBytecode/"; + + /** + * Loads shared corpus of dotted class names for tests and benchmarks. + * + * @return large list of dotted class names + */ + public static List loadClassNames() { + try (InputStream in = + requireNonNull( + SampleClasses.class.getResourceAsStream("sample_class_names.txt"), + "sample_class_names.txt"); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, UTF_8))) { + return reader.lines().collect(Collectors.toList()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } /** * Loads all class bytecode from the named sample bytecode jar. @@ -52,8 +74,8 @@ public static List loadBytecode(String sampleJar) { }) .filter(Objects::nonNull) .collect(Collectors.toList()); - } catch (IOException ex) { - throw new UncheckedIOException(ex); + } catch (IOException e) { + throw new UncheckedIOException(e); } } } diff --git a/utils/src/test/resources/sample_class_names.txt b/testing/src/main/resources/datadog/instrument/testing/sample_class_names.txt similarity index 100% rename from utils/src/test/resources/sample_class_names.txt rename to testing/src/main/resources/datadog/instrument/testing/sample_class_names.txt diff --git a/utils/src/jmh/java/datadog/instrument/utils/ClassInfoCacheBenchmark.java b/utils/src/jmh/java/datadog/instrument/utils/ClassInfoCacheBenchmark.java index 358c14c..44c2ef8 100644 --- a/utils/src/jmh/java/datadog/instrument/utils/ClassInfoCacheBenchmark.java +++ b/utils/src/jmh/java/datadog/instrument/utils/ClassInfoCacheBenchmark.java @@ -3,12 +3,9 @@ import static java.util.concurrent.TimeUnit.MICROSECONDS; import static org.openjdk.jmh.annotations.Mode.AverageTime; -import java.io.IOException; -import java.io.UncheckedIOException; +import datadog.instrument.testing.SampleClasses; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.List; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -38,11 +35,7 @@ public class ClassInfoCacheBenchmark { @Setup(Level.Trial) public void setup() { - try { - classNames = Files.readAllLines(Paths.get("src/test/resources/sample_class_names.txt")); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + classNames = SampleClasses.loadClassNames(); cl = URLClassLoader.newInstance(new URL[0]); cache = new ClassInfoCache<>(cacheSize); infoToShare = new Object(); diff --git a/utils/src/jmh/java/datadog/instrument/utils/ClassNameFilterBenchmark.java b/utils/src/jmh/java/datadog/instrument/utils/ClassNameFilterBenchmark.java index 25864b9..e63dc87 100644 --- a/utils/src/jmh/java/datadog/instrument/utils/ClassNameFilterBenchmark.java +++ b/utils/src/jmh/java/datadog/instrument/utils/ClassNameFilterBenchmark.java @@ -3,10 +3,7 @@ import static java.util.concurrent.TimeUnit.MICROSECONDS; import static org.openjdk.jmh.annotations.Mode.AverageTime; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Paths; +import datadog.instrument.testing.SampleClasses; import java.util.List; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -34,11 +31,7 @@ public class ClassNameFilterBenchmark { @Setup(Level.Trial) public void setup() { - try { - classNames = Files.readAllLines(Paths.get("src/test/resources/sample_class_names.txt")); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + classNames = SampleClasses.loadClassNames(); cache = new ClassNameFilter(cacheSize); } diff --git a/utils/src/jmh/java/datadog/instrument/utils/ClassNameTrieBenchmark.java b/utils/src/jmh/java/datadog/instrument/utils/ClassNameTrieBenchmark.java index 22cad91..b7d1388 100644 --- a/utils/src/jmh/java/datadog/instrument/utils/ClassNameTrieBenchmark.java +++ b/utils/src/jmh/java/datadog/instrument/utils/ClassNameTrieBenchmark.java @@ -3,10 +3,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.openjdk.jmh.annotations.Mode.AverageTime; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Paths; +import datadog.instrument.testing.SampleClasses; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -36,11 +33,7 @@ public class ClassNameTrieBenchmark { @Setup(Level.Trial) public void setup() { - try { - classNames = Files.readAllLines(Paths.get("src/test/resources/sample_class_names.txt")); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + classNames = SampleClasses.loadClassNames(); classNameTrie = buildClassNameTrie(); radixTrie = buildRadixTrie(); }