dd-trace-java
dd-trace-java copied to clipboard
Matcher Cache Builder
Matcher Cache Builder
Aims to speedup startup time by using a pre-built matcher cache. It's comprised of two parts:
- Matcher Cache Builder CLI
- Matcher Cache agent param
How to use
- Build Matcher Cache
Run Agent jar with -mc for usage instruction:
$ java -jar dd-java-trace.jar -mc
Matcher Cache Builder CLI usage: -o output-data-file {-cp class-path} [-r csv-report-file]
-o (output file) It is a mandatory param for the output binary Matcher Cache Data file path. If such a file aready exists, it will be replaced.
-r (report file) It is an optional param for the Matcher Cache builder report file path.
-cp (classpath) It can point to a directory that contains class files, jars, fat-jars or jmods. -cp can be used more than once.
Matcher Cache Builder searches for all the classes in provided class paths (-cp), dd-trace-jave agent classes, and the current JDK classes (specified in the JAVA_HOME env var).
It tries to load each class and checks whether class is going to be instrumented or not and saves this information into the output data file. This output Matcher Cache Data file is passed into the agent.
In order to see which classes were found and where along with the matcher resolution use -r to generate a report file.
- Use Matcher Cache Builder
In order to use a genreated matcher cache data file it needs to be passed as a java property to the java agent:
-Ddd.prebuilt.matcher.data.file=<path-to-generated-matcher-cache-data-file>
Check logs at the java agent startup to see whether the matcher cache was able to read cache data or not.
Matcher Cache JFR events
When Matcher Cache is being used it emits next JFR events:
datadog.trace.agent.MatcherCacheMissfor classes that where not found it the cachedatadog.trace.agent.MatcherCacheLoadingthe time it took to load cache data
Class Transformation JFR events
When Agent loads classes it produces datadog.trace.agent.ClassTransformation events.
It has next properties:
- internal class name
- class size in bytes
- class difference after transformation
- a flag whether the class has been transformed or skipped
- duration
Results with and without the matcher cache:

Matcher cache file sizes:
72K | play-java-chatroom-example-j11 82K | play-java-akka-cluster-example-j8 56K | play-scala-chatroom-example-j11 76K | play-scala-grpc-example-j8 128K | spring-boot-realworld-example-app-j11
I notice this only runs the matcher against loaded classes - all the byte-buddy matchers are designed so they can run against bytecode, ie. the class resource, without having to load the class.
There are a number of benefits of running these ahead-of-time matchers against bytecode:
- You can start with a simple search of resources, but then go on to support incremental generation as part of the build
- You can get match results for classes which can't be loaded without the right environment
- You can avoid a lot of complicated class-loading
- You avoid triggering static initializers that might have side-effects on the system
How hard would it be to drive this by searching class resources rather than forcibly loading classes?
I notice this only runs the matcher against loaded classes - all the byte-buddy matchers are designed so they can run against bytecode, ie. the class resource, without having to load the class.
There are a number of benefits of running these ahead-of-time matchers against bytecode:
1. You can start with a simple search of resources, but then go on to support incremental generation as part of the build 2. You can get match results for classes which can't be loaded without the right environment 3. You can avoid a lot of complicated class-loading 4. You avoid triggering static initializers that might have side-effects on the systemHow hard would it be to drive this by searching class resources rather than forcibly loading classes?
Thanks for the suggestion, Stuart. I've reworked Matcher Cache Builder to avoid class loading.
Can you add in how you generated the binary files that are used in the tests?
Do you mean jars, classes and jmod files? I built them manually. I don't think that adding a build script for them would be any useful and will only over complicate our build. Also creating a build script for them would include some confusing steps that I deliberately made to make sure that Matcher Cache Builder finds classes even if they have non-standard folder structure, renamed files or exist within a jar inside another jar. This includes renaming class files, changing class file paths, wrapping jar into another jar, generating jmod, building multi-release jars, etc
Closing this as similar idea to persist matching result is implemented in #5026