Skip to content

Commit 425276d

Browse files
authored
Add Probe Metadata (#9723)
Introducing ProbeMetadata class to help get probe from instrumented code. Instead of getting the probe instance from a map based on probeId we are directly getting it from an array that is filled at instrumentation time. This way it's cheaper and abstracted the way to get probe definition to evaluate conditions for example. In instrumented code, instead of referring the probe by the probeId hard-coded we are using index in probe metadata array. ProbeMetadata class encapsulate an AtomicReferenceArray to make sure every cell as a volatile-style access and provide linear way to remove or add into this array. For now linear scanning is fine as we don't expect a lot of probes in a same location. Could improve on that using bitmaps later if require. Instrumentation is changed to push int arrays instead of String arrays and can be optimize later to accept static arguments instead of varargs/array instead.
1 parent 7a9a005 commit 425276d

36 files changed

+307
-181
lines changed

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/CapturedContext.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,14 @@ public void freeze(TimeoutChecker timeoutChecker) {
294294
}
295295

296296
public Status evaluate(
297-
String encodedProbeId,
298297
ProbeImplementation probeImplementation,
299298
String thisClassName,
300299
long startTimestamp,
301300
MethodLocation methodLocation) {
302301
Status status =
303-
statusByProbeId.computeIfAbsent(encodedProbeId, key -> probeImplementation.createStatus());
302+
statusByProbeId.computeIfAbsent(
303+
probeImplementation.getProbeId().getEncodedId(),
304+
key -> probeImplementation.createStatus());
304305
if (methodLocation == MethodLocation.EXIT && startTimestamp > 0) {
305306
duration = System.nanoTime() - startTimestamp;
306307
addExtension(
@@ -326,6 +327,18 @@ public Status getStatus(String encodedProbeId) {
326327
return result;
327328
}
328329

330+
public Status getStatus(int probeIndex) {
331+
ProbeImplementation probeImplementation = DebuggerContext.resolveProbe(probeIndex);
332+
if (probeImplementation != null) {
333+
return getStatus(probeImplementation.getProbeId().getEncodedId());
334+
}
335+
Status result = statusByProbeId.get(ProbeImplementation.UNKNOWN.getProbeId().getEncodedId());
336+
if (result == null) {
337+
return Status.EMPTY_STATUS;
338+
}
339+
return result;
340+
}
341+
329342
@Override
330343
public boolean equals(Object o) {
331344
if (this == o) return true;

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/DebuggerContext.java

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public String tag() {
5151
}
5252

5353
public interface ProbeResolver {
54-
ProbeImplementation resolve(String encodedProbeId);
54+
ProbeImplementation resolve(int probeIndex);
5555
}
5656

5757
public interface ClassFilter {
@@ -144,16 +144,13 @@ public static void initCodeOrigin(CodeOriginRecorder codeOriginRecorder) {
144144
DebuggerContext.codeOriginRecorder = codeOriginRecorder;
145145
}
146146

147-
/**
148-
* Returns the probe details based on the probe id provided. If no probe is found, try to
149-
* re-transform the class using the callingClass parameter No-op if no implementation available
150-
*/
151-
public static ProbeImplementation resolveProbe(String id) {
147+
/** Returns the probe details based on the probe idx provided. */
148+
public static ProbeImplementation resolveProbe(int probeIndex) {
152149
ProbeResolver resolver = probeResolver;
153150
if (resolver == null) {
154151
return null;
155152
}
156-
return resolver.resolve(id);
153+
return resolver.resolve(probeIndex);
157154
}
158155

159156
/**
@@ -253,7 +250,7 @@ public static DebuggerSpan createSpan(String probeId, String operationName, Stri
253250
*
254251
* @return true if can proceed to capture data
255252
*/
256-
public static boolean isReadyToCapture(Class<?> callingClass, String... encodedProbeIds) {
253+
public static boolean isReadyToCapture(Class<?> callingClass, int... probeIndices) {
257254
try {
258255
return checkAndSetInProbe();
259256
} catch (Exception ex) {
@@ -287,21 +284,17 @@ public static void evalContext(
287284
Class<?> callingClass,
288285
long startTimestamp,
289286
MethodLocation methodLocation,
290-
String... encodedProbeIds) {
287+
int... probeIndices) {
291288
try {
292289
boolean needFreeze = false;
293-
for (String encodedProbeId : encodedProbeIds) {
294-
ProbeImplementation probeImplementation = resolveProbe(encodedProbeId);
290+
for (int probeIndex : probeIndices) {
291+
ProbeImplementation probeImplementation = resolveProbe(probeIndex);
295292
if (probeImplementation == null) {
296293
continue;
297294
}
298295
CapturedContext.Status status =
299296
context.evaluate(
300-
encodedProbeId,
301-
probeImplementation,
302-
callingClass.getTypeName(),
303-
startTimestamp,
304-
methodLocation);
297+
probeImplementation, callingClass.getTypeName(), startTimestamp, methodLocation);
305298
needFreeze |= status.shouldFreezeContext();
306299
}
307300
// only freeze the context when we have at lest one snapshot probe, and we should send
@@ -321,20 +314,16 @@ public static void evalContext(
321314
* conditions and commit snapshot to send it if needed. This is for line probes.
322315
*/
323316
public static void evalContextAndCommit(
324-
CapturedContext context, Class<?> callingClass, int line, String... encodedProbeIds) {
317+
CapturedContext context, Class<?> callingClass, int line, int... probeIndices) {
325318
try {
326319
List<ProbeImplementation> probeImplementations = new ArrayList<>();
327-
for (String encodedProbeId : encodedProbeIds) {
328-
ProbeImplementation probeImplementation = resolveProbe(encodedProbeId);
320+
for (int probeIndex : probeIndices) {
321+
ProbeImplementation probeImplementation = resolveProbe(probeIndex);
329322
if (probeImplementation == null) {
330323
continue;
331324
}
332325
context.evaluate(
333-
encodedProbeId,
334-
probeImplementation,
335-
callingClass.getTypeName(),
336-
-1,
337-
MethodLocation.DEFAULT);
326+
probeImplementation, callingClass.getTypeName(), -1, MethodLocation.DEFAULT);
338327
probeImplementations.add(probeImplementation);
339328
}
340329
for (ProbeImplementation probeImplementation : probeImplementations) {
@@ -345,9 +334,9 @@ public static void evalContextAndCommit(
345334
}
346335
}
347336

348-
public static void codeOrigin(String probeId) {
337+
public static void codeOrigin(int probeIndex) {
349338
try {
350-
ProbeImplementation probe = probeResolver.resolve(probeId);
339+
ProbeImplementation probe = probeResolver.resolve(probeIndex);
351340
if (probe != null) {
352341
probe.commit(
353342
CapturedContext.EMPTY_CONTEXT, CapturedContext.EMPTY_CONTEXT, Collections.emptyList());
@@ -365,16 +354,16 @@ public static void commit(
365354
CapturedContext entryContext,
366355
CapturedContext exitContext,
367356
List<CapturedContext.CapturedThrowable> caughtExceptions,
368-
String... encodedProbeIds) {
357+
int... probeIndices) {
369358
try {
370359
if (entryContext == CapturedContext.EMPTY_CONTEXT
371360
&& exitContext == CapturedContext.EMPTY_CONTEXT) {
372361
// rate limited
373362
return;
374363
}
375-
for (String encodedProbeId : encodedProbeIds) {
376-
CapturedContext.Status entryStatus = entryContext.getStatus(encodedProbeId);
377-
CapturedContext.Status exitStatus = exitContext.getStatus(encodedProbeId);
364+
for (int probeIndex : probeIndices) {
365+
CapturedContext.Status entryStatus = entryContext.getStatus(probeIndex);
366+
CapturedContext.Status exitStatus = exitContext.getStatus(probeIndex);
378367
ProbeImplementation probeImplementation;
379368
if (entryStatus.probeImplementation != ProbeImplementation.UNKNOWN
380369
&& (entryStatus.probeImplementation.getEvaluateAt() == MethodLocation.ENTRY
@@ -383,7 +372,7 @@ public static void commit(
383372
} else if (exitStatus.probeImplementation.getEvaluateAt() == MethodLocation.EXIT) {
384373
probeImplementation = exitStatus.probeImplementation;
385374
} else {
386-
throw new IllegalStateException("no probe details for " + encodedProbeId);
375+
throw new IllegalStateException("no probe details for " + probeIndex);
387376
}
388377
probeImplementation.commit(entryContext, exitContext, caughtExceptions);
389378
}

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ConfigurationUpdater.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ DebuggerTransformer supply(
4747
Config tracerConfig,
4848
Configuration configuration,
4949
DebuggerTransformer.InstrumentationListener listener,
50+
ProbeMetadata probeMetadata,
5051
DebuggerSink debuggerSink);
5152
}
5253

@@ -61,6 +62,7 @@ DebuggerTransformer supply(
6162
private volatile Configuration currentConfiguration;
6263
private DebuggerTransformer currentTransformer;
6364
private final Map<String, ProbeDefinition> appliedDefinitions = new ConcurrentHashMap<>();
65+
private final ProbeMetadata probeMetadata = new ProbeMetadata();
6466
private final DebuggerSink sink;
6567
private final ClassesToRetransformFinder finder;
6668
private final String serviceName;
@@ -119,6 +121,10 @@ public void handleException(String configId, Exception ex) {
119121
sink.getProbeStatusSink().addError(probeId, ex);
120122
}
121123

124+
ProbeMetadata getProbeMetadata() {
125+
return probeMetadata;
126+
}
127+
122128
private ProbeId extractPrefix(String prefix, String configId) {
123129
return new ProbeId(configId.substring(prefix.length()), 0);
124130
}
@@ -201,7 +207,11 @@ private void installNewDefinitions(Configuration newConfiguration) {
201207
// install new probe definitions
202208
DebuggerTransformer newTransformer =
203209
transformerSupplier.supply(
204-
Config.get(), newConfiguration, this::recordInstrumentationProgress, sink);
210+
Config.get(),
211+
newConfiguration,
212+
this::recordInstrumentationProgress,
213+
probeMetadata,
214+
sink);
205215
instrumentation.addTransformer(newTransformer, true);
206216
currentTransformer = newTransformer;
207217
LOGGER.debug("New transformer installed");
@@ -231,6 +241,7 @@ private void retransformClasses(List<Class<?>> classesToBeTransformed) {
231241
private void storeDebuggerDefinitions(ConfigurationComparer changes) {
232242
for (ProbeDefinition definition : changes.getRemovedDefinitions()) {
233243
appliedDefinitions.remove(definition.getProbeId().getEncodedId());
244+
probeMetadata.removeProbe(definition.getProbeId().getEncodedId());
234245
}
235246
for (ProbeDefinition definition : changes.getAddedDefinitions()) {
236247
appliedDefinitions.put(definition.getProbeId().getEncodedId(), definition);
@@ -240,12 +251,12 @@ private void storeDebuggerDefinitions(ConfigurationComparer changes) {
240251

241252
// /!\ This is called potentially by multiple threads from the instrumented code /!\
242253
@Override
243-
public ProbeImplementation resolve(String encodedProbeId) {
244-
ProbeDefinition definition = appliedDefinitions.get(encodedProbeId);
245-
if (definition == null) {
246-
ratelimitedLogger.warn(SEND_TELEMETRY, "Cannot resolve probe id={}", encodedProbeId);
254+
public ProbeImplementation resolve(int probeIndex) {
255+
ProbeImplementation probeImplementation = probeMetadata.getProbe(probeIndex);
256+
if (probeImplementation == null) {
257+
ratelimitedLogger.warn(SEND_TELEMETRY, "Cannot resolve probe index={}", probeIndex);
247258
}
248-
return definition;
259+
return probeImplementation;
249260
}
250261

251262
private static void applyRateLimiter(

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,8 @@ static ClassFileTransformer setupInstrumentTheWorldTransformer(
394394
Config config, Instrumentation instrumentation, DebuggerSink debuggerSink) {
395395
LOGGER.info("install Instrument-The-World transformer");
396396
DebuggerTransformer transformer =
397-
createTransformer(config, Configuration.builder().build(), null, debuggerSink);
397+
createTransformer(
398+
config, Configuration.builder().build(), null, new ProbeMetadata(), debuggerSink);
398399
DebuggerContext.initProbeResolver(transformer::instrumentTheWorldResolver);
399400
instrumentation.addTransformer(transformer);
400401
return transformer;
@@ -412,8 +413,9 @@ private static DebuggerTransformer createTransformer(
412413
Config config,
413414
Configuration configuration,
414415
DebuggerTransformer.InstrumentationListener listener,
416+
ProbeMetadata probeMetadata,
415417
DebuggerSink debuggerSink) {
416-
return new DebuggerTransformer(config, configuration, listener, debuggerSink);
418+
return new DebuggerTransformer(config, configuration, listener, probeMetadata, debuggerSink);
417419
}
418420

419421
static void stop() {

0 commit comments

Comments
 (0)