Skip to content

Commit 837b738

Browse files
authored
Make JMH executor threads look like event loop threads (#14444)
Motivation: Our buffer allocators make specific optimisations for event loop threads. Thus it makes sense that our benchmark executors look as much like event loops as possible, to trigger those optimisations. Modification: Make sure that JMH executor threads add themselves to the `ThreadExecutorMap` so that they look like event loop threads. Result: The various `ByteBufAllocator*Benchmarks` show improved performance because they now go through event-loop optimised code paths. When needed, it's still possible to disable this behavior by disabling the custom harness executor. That functionality has been part of our custom JMH harness for a long time.
1 parent a434eef commit 837b738

File tree

1 file changed

+61
-2
lines changed

1 file changed

+61
-2
lines changed

microbench/src/main/java/io/netty/microbench/util/AbstractMicrobenchmark.java

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,24 @@
1515
*/
1616
package io.netty.microbench.util;
1717

18+
import io.netty.util.concurrent.AbstractEventExecutor;
19+
import io.netty.util.concurrent.AbstractScheduledEventExecutor;
20+
import io.netty.util.concurrent.DefaultEventExecutor;
21+
import io.netty.util.concurrent.DefaultPromise;
1822
import io.netty.util.concurrent.DefaultThreadFactory;
23+
import io.netty.util.concurrent.EventExecutor;
24+
import io.netty.util.concurrent.FastThreadLocalThread;
25+
import io.netty.util.concurrent.Future;
26+
import io.netty.util.concurrent.SingleThreadEventExecutor;
1927
import io.netty.util.internal.SystemPropertyUtil;
28+
import io.netty.util.internal.ThreadExecutorMap;
2029
import io.netty.util.internal.logging.InternalLogger;
2130
import io.netty.util.internal.logging.InternalLoggerFactory;
2231

2332
import java.util.concurrent.LinkedBlockingQueue;
2433
import java.util.concurrent.ThreadPoolExecutor;
2534
import java.util.concurrent.TimeUnit;
35+
import java.util.concurrent.TimeoutException;
2636

2737
import org.openjdk.jmh.annotations.Fork;
2838
import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
@@ -36,11 +46,60 @@ public class AbstractMicrobenchmark extends AbstractMicrobenchmarkBase {
3646
protected static final int DEFAULT_FORKS = 2;
3747

3848
public static final class HarnessExecutor extends ThreadPoolExecutor {
39-
private final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractMicrobenchmark.class);
49+
private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractMicrobenchmark.class);
4050

4151
public HarnessExecutor(int maxThreads, String prefix) {
4252
super(maxThreads, maxThreads, 0, TimeUnit.MILLISECONDS,
43-
new LinkedBlockingQueue<Runnable>(), new DefaultThreadFactory(prefix));
53+
new LinkedBlockingQueue<Runnable>(),
54+
new DefaultThreadFactory(prefix));
55+
EventExecutor eventExecutor = new AbstractEventExecutor() {
56+
@Override
57+
public void shutdown() {
58+
throw new UnsupportedOperationException();
59+
}
60+
61+
@Override
62+
public boolean inEventLoop(Thread thread) {
63+
return thread instanceof FastThreadLocalThread;
64+
}
65+
66+
@Override
67+
public boolean isShuttingDown() {
68+
throw new UnsupportedOperationException();
69+
}
70+
71+
@Override
72+
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
73+
throw new UnsupportedOperationException();
74+
}
75+
76+
@Override
77+
public Future<?> terminationFuture() {
78+
throw new UnsupportedOperationException();
79+
}
80+
81+
@Override
82+
public boolean isShutdown() {
83+
throw new UnsupportedOperationException();
84+
}
85+
86+
@Override
87+
public boolean isTerminated() {
88+
throw new UnsupportedOperationException();
89+
}
90+
91+
@Override
92+
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
93+
throw new UnsupportedOperationException();
94+
}
95+
96+
@Override
97+
public void execute(Runnable command) {
98+
throw new UnsupportedOperationException();
99+
}
100+
};
101+
setThreadFactory(ThreadExecutorMap.apply(getThreadFactory(), eventExecutor));
102+
44103
logger.debug("Using harness executor");
45104
}
46105
}

0 commit comments

Comments
 (0)