Improve benchmark and caching optimizations.
MODIFY
dd-java-agent/benchmark/benchmark.gradle
dd-java-agent/benchmark/benchmark.gradle
@@ -60,13 +60,12 @@ task jmhAgent(type: JavaExec, dependsOn: project.tasks.jmhCompileGeneratedClasse
main = "org.openjdk.jmh.Main"
args += ["-tu", "us"]
args += ["-bm", "avgt"]
- args += ["-prof", "stack"]
-// args += ["-r", "5s"]
-// args += ["-i", "5"]
+// args += ["-prof", "stack:lines=5;detailLine=true;period=5;excludePackages=true"]
args += ["-f", "1"]
args += ["-foe", "true"]
-// args += ["-w", "2s"]
+
// args += ["-wi", "2"]
+// args += ["-i", "5"]
}
tasks.jmhAgent.dependsOn project(':dd-java-agent').shadowJar

MODIFY
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/ClassRetransformingBenchmark.java
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/ClassRetransformingBenchmark.java
package com.datadoghq.benchmark;
-import com.datadoghq.benchmark.classes.DeepClass;
-import com.datadoghq.benchmark.classes.SimpleClass;
+import com.datadoghq.benchmark.classes.TracedClass;
+import com.datadoghq.benchmark.classes.UntracedClass;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.reflect.Field;
@@ -54,13 +54,14 @@ public class ClassRetransformingBenchmark {
}
@Benchmark
- public void testSimpleRetransform(final BenchmarkState state) throws UnmodifiableClassException {
- state.inst.retransformClasses(SimpleClass.class);
+ public void testUntracedRetransform(final BenchmarkState state)
+ throws UnmodifiableClassException {
+ state.inst.retransformClasses(UntracedClass.class);
}
@Benchmark
- public void testDeepRetransform(final BenchmarkState state) throws UnmodifiableClassException {
- state.inst.retransformClasses(DeepClass.class);
+ public void testTracedRetransform(final BenchmarkState state) throws UnmodifiableClassException {
+ state.inst.retransformClasses(TracedClass.class);
}
@Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.2.jar")

MODIFY
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/A.java
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/A.java
package com.datadoghq.benchmark.classes;
-import com.datadoghq.trace.Trace;
-
public interface A {
- @Trace
- void interfaceTrace();
+ void a();
}

MODIFY
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/B.java
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/B.java
package com.datadoghq.benchmark.classes;
-import com.datadoghq.trace.Trace;
-
public interface B extends A {
- @Trace
- void something();
+ void b();
}

MODIFY
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/C.java
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/C.java
package com.datadoghq.benchmark.classes;
public interface C extends B {
- void somethingElse();
+ void c();
}

ADD
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/D.java
+package com.datadoghq.benchmark.classes;
+
+public interface D extends C {
+ void d();
+}

DELETE
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/DeepClass.java
-package com.datadoghq.benchmark.classes;
-
-import com.datadoghq.trace.Trace;
-
-public class DeepClass implements C {
-
- @Override
- public void interfaceTrace() {
- }
-
- @Override
- public void something() {
- }
-
- @Trace
- @Override
- public void somethingElse() {
- }
-}

ADD
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/E.java
+package com.datadoghq.benchmark.classes;
+
+public interface E extends D {
+ void e();
+}

ADD
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/F.java
+package com.datadoghq.benchmark.classes;
+
+public abstract class F implements E {
+ public abstract void f();
+
+ public void g() {}
+}

DELETE
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/SimpleClass.java
-package com.datadoghq.benchmark.classes;
-
-import com.datadoghq.trace.Trace;
-
-public class SimpleClass {
- @Trace
- public void aMethodToTrace() {
- }
-}

ADD
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/TracedClass.java
+package com.datadoghq.benchmark.classes;
+
+import com.datadoghq.trace.Trace;
+
+public class TracedClass extends UntracedClass {
+ @Trace
+ @Override
+ public void f() {}
+
+ @Trace
+ @Override
+ public void e() {}
+
+ @Trace
+ @Override
+ public void d() {}
+
+ @Trace
+ @Override
+ public void c() {}
+
+ @Trace
+ @Override
+ public void b() {}
+
+ @Trace
+ @Override
+ public void a() {}
+}

ADD
dd-java-agent/benchmark/src/jmh/java/com/datadoghq/benchmark/classes/UntracedClass.java
+package com.datadoghq.benchmark.classes;
+
+public class UntracedClass extends F {
+ @Override
+ public void f() {}
+
+ @Override
+ public void e() {}
+
+ @Override
+ public void d() {}
+
+ @Override
+ public void c() {}
+
+ @Override
+ public void b() {}
+
+ @Override
+ public void a() {}
+}

MODIFY
dd-java-agent/tooling/src/main/java/dd/trace/ClassLoaderMatcher.java
dd-java-agent/tooling/src/main/java/dd/trace/ClassLoaderMatcher.java
package dd.trace;
+import java.util.WeakHashMap;
import net.bytebuddy.matcher.ElementMatcher;
public class ClassLoaderMatcher {
@@ -45,6 +46,8 @@ public class ClassLoaderMatcher {
public static class ClassLoaderHasClassMatcher
extends ElementMatcher.Junction.AbstractBase<ClassLoader> {
+ private final WeakHashMap<ClassLoader, Boolean> cache = new WeakHashMap<>();
+
private final String[] names;
private ClassLoaderHasClassMatcher(final String... names) {
@@ -53,23 +56,32 @@ public class ClassLoaderMatcher {
@Override
public boolean matches(final ClassLoader target) {
- try {
if (target != null) {
+ synchronized (target) {
+ if (cache.containsKey(target)) {
+ return cache.get(target);
+ }
+ try {
for (final String name : names) {
Class.forName(name, false, target);
}
+ cache.put(target, true);
return true;
- }
- return false;
} catch (final ClassNotFoundException e) {
+ cache.put(target, false);
return false;
}
}
}
+ return false;
+ }
+ }
public static class ClassLoaderHasClassWithFieldMatcher
extends ElementMatcher.Junction.AbstractBase<ClassLoader> {
+ private final WeakHashMap<ClassLoader, Boolean> cache = new WeakHashMap<>();
+
private final String className;
private final String fieldName;
@@ -80,18 +92,26 @@ public class ClassLoaderMatcher {
@Override
public boolean matches(final ClassLoader target) {
- try {
if (target != null) {
+ synchronized (target) {
+ if (cache.containsKey(target)) {
+ return cache.get(target);
+ }
+ try {
final Class<?> aClass = Class.forName(className, false, target);
aClass.getDeclaredField(fieldName);
+ cache.put(target, true);
return true;
- }
- return false;
} catch (final ClassNotFoundException e) {
+ cache.put(target, false);
return false;
} catch (final NoSuchFieldException e) {
+ cache.put(target, false);
return false;
}
}
}
+ return false;
+ }
+ }
}

Improve benchmark and caching optimizations.