-
Notifications
You must be signed in to change notification settings - Fork 292
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support JDK-21 virtual thread executor (#6789)
add JAVA_21_HOME to workflows and create TaskRunnerInstrumentation
- Loading branch information
Showing
8 changed files
with
214 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
...a-agent/instrumentation/java-concurrent/src/latestDepTest/groovy/VirtualThreadTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import datadog.trace.agent.test.AgentTestRunner | ||
import datadog.trace.api.Trace | ||
import datadog.trace.core.DDSpan | ||
import spock.lang.Shared | ||
|
||
import java.util.concurrent.Callable | ||
import java.util.concurrent.ExecutorCompletionService | ||
import java.util.concurrent.Executors | ||
import java.util.concurrent.TimeUnit | ||
|
||
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope | ||
|
||
class VirtualThreadTest extends AgentTestRunner { | ||
|
||
@Shared | ||
def executeRunnable = { e, c -> e.execute((Runnable) c) } | ||
@Shared | ||
def submitRunnable = { e, c -> e.submit((Runnable) c) } | ||
@Shared | ||
def submitCallable = { e, c -> e.submit((Callable) c) } | ||
@Shared | ||
def submitRunnableExecutorCompletionService = { ecs, c -> ecs.submit((Runnable) c, null) } | ||
@Shared | ||
def invokeAll = { e, c -> e.invokeAll([(Callable) c]) } | ||
@Shared | ||
def invokeAllTimeout = { e, c -> e.invokeAll([(Callable) c], 10, TimeUnit.SECONDS) } | ||
@Shared | ||
def invokeAny = { e, c -> e.invokeAny([(Callable) c]) } | ||
@Shared | ||
def invokeAnyTimeout = { e, c -> e.invokeAny([(Callable) c], 10, TimeUnit.SECONDS) } | ||
|
||
def "virtualThreadPool #name"() { | ||
setup: | ||
def pool = poolImpl | ||
def m = method | ||
|
||
new Runnable() { | ||
@Override | ||
@Trace(operationName = "parent") | ||
void run() { | ||
activeScope().setAsyncPropagation(true) | ||
// this child will have a span | ||
m(pool, new JavaAsyncChild()) | ||
// this child won't | ||
m(pool, new JavaAsyncChild(false, false)) | ||
blockUntilChildSpansFinished(1) | ||
} | ||
}.run() | ||
|
||
TEST_WRITER.waitForTraces(1) | ||
List<DDSpan> trace = TEST_WRITER.get(0) | ||
|
||
expect: | ||
TEST_WRITER.size() == 1 | ||
trace.size() == 2 | ||
trace.get(0).operationName == "parent" | ||
trace.get(1).operationName == "asyncChild" | ||
trace.get(1).parentId == trace.get(0).spanId | ||
|
||
cleanup: | ||
if (pool?.hasProperty("shutdown")) { | ||
pool?.shutdown() | ||
} | ||
|
||
where: | ||
// spotless:off | ||
name | method | poolImpl | ||
"execute Runnable" | executeRunnable | Executors.newVirtualThreadPerTaskExecutor() | ||
"submit Runnable" | submitRunnable | Executors.newVirtualThreadPerTaskExecutor() | ||
"submit Callable" | submitCallable | Executors.newVirtualThreadPerTaskExecutor() | ||
"submit Runnable ECS" | submitRunnableExecutorCompletionService | new ExecutorCompletionService<>(Executors.newVirtualThreadPerTaskExecutor()) | ||
"submit Callable ECS" | submitCallable | new ExecutorCompletionService<>(Executors.newVirtualThreadPerTaskExecutor()) | ||
"invokeAll" | invokeAll | Executors.newVirtualThreadPerTaskExecutor() | ||
"invokeAll with timeout" | invokeAllTimeout | Executors.newVirtualThreadPerTaskExecutor() | ||
"invokeAny" | invokeAny | Executors.newVirtualThreadPerTaskExecutor() | ||
"invokeAny with timeout" | invokeAnyTimeout | Executors.newVirtualThreadPerTaskExecutor() | ||
// spotless:on | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
dd-java-agent/instrumentation/java-concurrent/src/latestDepTest/java/JavaAsyncChild.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import datadog.trace.api.Trace; | ||
import java.util.concurrent.Callable; | ||
import java.util.concurrent.ForkJoinTask; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
public class JavaAsyncChild extends ForkJoinTask implements Runnable, Callable { | ||
private final AtomicBoolean blockThread; | ||
private final boolean doTraceableWork; | ||
|
||
public JavaAsyncChild() { | ||
this(true, false); | ||
} | ||
|
||
@Override | ||
public Object getRawResult() { | ||
return null; | ||
} | ||
|
||
@Override | ||
protected void setRawResult(final Object value) {} | ||
|
||
@Override | ||
protected boolean exec() { | ||
runImpl(); | ||
return true; | ||
} | ||
|
||
public JavaAsyncChild(final boolean doTraceableWork, final boolean blockThread) { | ||
this.doTraceableWork = doTraceableWork; | ||
this.blockThread = new AtomicBoolean(blockThread); | ||
} | ||
|
||
public void unblock() { | ||
blockThread.set(false); | ||
} | ||
|
||
@Override | ||
public void run() { | ||
runImpl(); | ||
} | ||
|
||
@Override | ||
public Object call() throws Exception { | ||
runImpl(); | ||
return null; | ||
} | ||
|
||
private void runImpl() { | ||
while (blockThread.get()) { | ||
// busy-wait to block thread | ||
} | ||
if (doTraceableWork) { | ||
asyncChild(); | ||
} | ||
} | ||
|
||
@Trace(operationName = "asyncChild") | ||
private void asyncChild() {} | ||
} |
61 changes: 61 additions & 0 deletions
61
...rc/main/java/datadog/trace/instrumentation/java/concurrent/TaskRunnerInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package datadog.trace.instrumentation.java.concurrent; | ||
|
||
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; | ||
import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.capture; | ||
import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.endTaskScope; | ||
import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.startTaskScope; | ||
import static java.util.Collections.singletonMap; | ||
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; | ||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
|
||
import com.google.auto.service.AutoService; | ||
import datadog.trace.agent.tooling.Instrumenter; | ||
import datadog.trace.agent.tooling.InstrumenterModule; | ||
import datadog.trace.bootstrap.InstrumentationContext; | ||
import datadog.trace.bootstrap.instrumentation.api.AgentScope; | ||
import datadog.trace.bootstrap.instrumentation.java.concurrent.State; | ||
import java.util.Map; | ||
import net.bytebuddy.asm.Advice; | ||
|
||
@AutoService(Instrumenter.class) | ||
public final class TaskRunnerInstrumentation extends InstrumenterModule.Tracing | ||
implements Instrumenter.ForBootstrap, Instrumenter.ForSingleType { | ||
public TaskRunnerInstrumentation() { | ||
super("java_concurrent", "task-runner"); | ||
} | ||
|
||
@Override | ||
public String instrumentedType() { | ||
return "java.util.concurrent.ThreadPerTaskExecutor$TaskRunner"; | ||
} | ||
|
||
@Override | ||
public Map<String, String> contextStore() { | ||
return singletonMap("java.lang.Runnable", State.class.getName()); | ||
} | ||
|
||
@Override | ||
public void methodAdvice(MethodTransformer transformer) { | ||
transformer.applyAdvice(isConstructor(), getClass().getName() + "$Construct"); | ||
transformer.applyAdvice(isMethod().and(named("run")), getClass().getName() + "$Run"); | ||
} | ||
|
||
public static final class Construct { | ||
@Advice.OnMethodExit | ||
public static void captureScope(@Advice.This Runnable task) { | ||
capture(InstrumentationContext.get(Runnable.class, State.class), task, true); | ||
} | ||
} | ||
|
||
public static final class Run { | ||
@Advice.OnMethodEnter | ||
public static AgentScope activate(@Advice.This Runnable task) { | ||
return startTaskScope(InstrumentationContext.get(Runnable.class, State.class), task); | ||
} | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class) | ||
public static void close(@Advice.Enter AgentScope scope) { | ||
endTaskScope(scope); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
#!/bin/sh | ||
|
||
JAVA_HOME=$JAVA_HOME_8_X64 JAVA_8_HOME=$JAVA_HOME_8_X64 JAVA_11_HOME=$JAVA_HOME_11_X64 JAVA_17_HOME=$JAVA_HOME_17_X64 ./gradlew dd-java-agent:build dd-java-agent:shadowJar --build-cache --parallel --no-daemon --max-workers=8 | ||
JAVA_HOME=$JAVA_HOME_8_X64 JAVA_8_HOME=$JAVA_HOME_8_X64 JAVA_11_HOME=$JAVA_HOME_11_X64 JAVA_17_HOME=$JAVA_HOME_17_X64 JAVA_21_HOME=$JAVA_HOME_21_X64 ./gradlew dd-java-agent:build dd-java-agent:shadowJar --build-cache --parallel --no-daemon --max-workers=8 | ||
cp workspace/dd-java-agent/build/libs/dd-java-agent-*.jar lib-injection/ | ||
rm lib-injection/*-sources.jar lib-injection/*-javadoc.jar | ||
mv lib-injection/*.jar lib-injection/dd-java-agent.jar | ||
echo "Java tracer copied to lib-injection folder" | ||
ls lib-injection/ | ||
ls lib-injection/ |