Skip to content

Commit efe0f8e

Browse files
dougqhclaude
andcommitted
Make ThreadSafeMapBenchmark lookup index per-thread (remove shared-counter contention)
nextLookupKey used a shared static counter incremented from all @threads(8) — a cache-line-contended race that floors the fastest reads and masks the very differences the benchmark compares (mirrors the per-thread index SingleThreadedMapBenchmark already uses, and the set-benchmark fix in #11721). Maps stay static/shared; only the lookup index goes per-thread via @State(Scope.Thread). Existing Javadoc numbers predate this and need a rerun. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0fddfc4 commit efe0f8e

1 file changed

Lines changed: 12 additions & 5 deletions

File tree

internal-api/src/jmh/java/datadog/trace/util/ThreadSafeMapBenchmark.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.openjdk.jmh.annotations.Benchmark;
1010
import org.openjdk.jmh.annotations.Fork;
1111
import org.openjdk.jmh.annotations.Measurement;
12+
import org.openjdk.jmh.annotations.Scope;
13+
import org.openjdk.jmh.annotations.State;
1214
import org.openjdk.jmh.annotations.Threads;
1315
import org.openjdk.jmh.annotations.Warmup;
1416

@@ -65,6 +67,7 @@
6567
@Warmup(iterations = 2)
6668
@Measurement(iterations = 3)
6769
@Threads(8)
70+
@State(Scope.Thread)
6871
public class ThreadSafeMapBenchmark {
6972
static final String[] INSERTION_KEYS = {
7073
"foo", "bar", "baz", "quux", "foobar", "foobaz", "key0", "key1", "key2", "key3"
@@ -84,16 +87,20 @@ static <T> T init(Supplier<T> supplier) {
8487
return supplier.get();
8588
}
8689

87-
static int sharedLookupIndex = 0;
90+
// Per-thread (@State(Scope.Thread)) so cycling the lookup key doesn't contend a shared counter.
91+
// The maps below stay static/shared (the point — concurrent reads of one map); only the index is
92+
// per-thread. A shared counter's cache-line ping-pong would otherwise floor the fastest reads
93+
// (e.g. FlatHashtable's lock-free probe), hiding exactly the differences this benchmark compares.
94+
int lookupIndex = 0;
8895

89-
static String nextLookupKey() {
96+
String nextLookupKey() {
9097
return nextLookupKey(EQUAL_KEYS);
9198
}
9299

93-
static String nextLookupKey(String[] keys) {
94-
int localIndex = ++sharedLookupIndex;
100+
String nextLookupKey(String[] keys) {
101+
int localIndex = ++lookupIndex;
95102
if (localIndex >= keys.length) {
96-
sharedLookupIndex = localIndex = 0;
103+
lookupIndex = localIndex = 0;
97104
}
98105
return keys[localIndex];
99106
}

0 commit comments

Comments
 (0)