Startup time affects everyone—users waiting for responses, developers testing features, and teams watching cloud costs. Datadog Application Performance Monitoring (APM) helps engineers understand performance throughout an application, including during startup. For Java, using APM involves attaching an agent to the JVM that automatically transforms classes to add observability, an approach known as instrumentation. Instrument too few places and you miss key details. Instrument too many and startup suffers. APM has to balance that trade-off, and the first step is deciding which classes to instrument—a problem called class matching.

Over the past 4 years, the Datadog APM team has reduced class-matching overhead by 30%. Optimizing class matching during startup is particularly challenging because the just-in-time (JIT) compiler has not yet optimized the matcher code, and profilers have not captured enough samples to identify hot spots. Instead, we relied on our knowledge of JVM internals to identify promising ideas and ran multiple experiments to validate our intuition.

One speculative optimization that paid off was encoding multiple class-name prefix matches ahead of time as a single JVM constant, loaded with a single bytecode instruction. In this post, we’ll explain how we developed that encoding and used it to replace a hand-rolled matcher of “uninteresting” classes.