Skip to content

Commit d6340d3

Browse files
apply rate limit to queue events
1 parent 919bf01 commit d6340d3

File tree

6 files changed

+56
-16
lines changed

6 files changed

+56
-16
lines changed

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/QueueTimerHelper.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
package datadog.trace.bootstrap.instrumentation.java.concurrent;
22

3+
import datadog.trace.api.config.ProfilingConfig;
34
import datadog.trace.api.profiling.QueueTiming;
45
import datadog.trace.api.profiling.Timer;
6+
import datadog.trace.api.sampling.PerRecordingRateLimiter;
57
import datadog.trace.bootstrap.ContextStore;
8+
import datadog.trace.bootstrap.config.provider.ConfigProvider;
69
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
710
import datadog.trace.bootstrap.instrumentation.jfr.InstrumentationBasedProfiling;
811

12+
import java.time.Duration;
13+
import java.time.temporal.ChronoUnit;
14+
915
public class QueueTimerHelper {
1016

17+
private static final PerRecordingRateLimiter RATE_LIMITER = new PerRecordingRateLimiter(Duration.of(500, ChronoUnit.MILLIS),
18+
10_000, // hard limit on queue events
19+
ConfigProvider.getInstance().getInteger(ProfilingConfig.PROFILING_UPLOAD_PERIOD,
20+
ProfilingConfig.PROFILING_UPLOAD_PERIOD_DEFAULT));
21+
1122
public static <T> void startQueuingTimer(
1223
ContextStore<T, State> taskContextStore, Class<?> schedulerClass, T task) {
1324
State state = taskContextStore.get(task);
@@ -17,7 +28,7 @@ public static <T> void startQueuingTimer(
1728
public static void startQueuingTimer(State state, Class<?> schedulerClass, Object task) {
1829
// avoid calling this before JFR is initialised because it will lead to reading the wrong
1930
// TSC frequency before JFR has set it up properly
20-
if (task != null && state != null && InstrumentationBasedProfiling.isJFRReady()) {
31+
if (task != null && state != null && InstrumentationBasedProfiling.isJFRReady() && RATE_LIMITER.permit()) {
2132
QueueTiming timing =
2233
(QueueTiming) AgentTracer.get().getProfilingContext().start(Timer.TimerType.QUEUEING);
2334
timing.setTask(task);

dd-java-agent/agent-bootstrap/src/main/java11/datadog/trace/bootstrap/instrumentation/jfr/WindowSampler.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import datadog.trace.api.sampling.AdaptiveSampler;
44
import java.time.Duration;
5-
import java.time.temporal.ChronoUnit;
65
import jdk.jfr.Event;
76
import jdk.jfr.EventType;
87

@@ -24,18 +23,4 @@ public void start() {
2423
public boolean sample() {
2524
return sampleType.isEnabled() && sampler.sample();
2625
}
27-
28-
protected static int samplingWindowsPerRecording(
29-
long uploadPeriodSeconds, Duration samplingWindow) {
30-
/*
31-
* Java8 doesn't have dividedBy#Duration so we have to implement poor man's version.
32-
* None of these durations should be big enough to warrant dealing with bigints.
33-
* We also do not care about nanoseconds here.
34-
*/
35-
return (int)
36-
Math.min(
37-
Duration.of(uploadPeriodSeconds, ChronoUnit.SECONDS).toMillis()
38-
/ samplingWindow.toMillis(),
39-
Integer.MAX_VALUE);
40-
}
4126
}

dd-java-agent/agent-bootstrap/src/main/java11/datadog/trace/bootstrap/instrumentation/jfr/backpressure/BackpressureSampler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.time.Duration;
66
import java.time.temporal.ChronoUnit;
77

8+
import static datadog.trace.api.sampling.PerRecordingRateLimiter.samplingWindowsPerRecording;
9+
810
final class BackpressureSampler extends WindowSampler<BackpressureSampleEvent> {
911
/*
1012
* Fixed 0.5 second sampling window.

dd-java-agent/agent-bootstrap/src/main/java11/datadog/trace/bootstrap/instrumentation/jfr/directallocation/DirectAllocationSampler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.time.Duration;
66
import java.time.temporal.ChronoUnit;
77

8+
import static datadog.trace.api.sampling.PerRecordingRateLimiter.samplingWindowsPerRecording;
9+
810
public class DirectAllocationSampler extends WindowSampler<DirectAllocationSampleEvent> {
911

1012
/*

dd-java-agent/agent-bootstrap/src/main/java11/datadog/trace/bootstrap/instrumentation/jfr/exceptions/ExceptionSampler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.time.Duration;
66
import java.time.temporal.ChronoUnit;
77

8+
import static datadog.trace.api.sampling.PerRecordingRateLimiter.samplingWindowsPerRecording;
9+
810
final class ExceptionSampler extends WindowSampler<ExceptionSampleEvent> {
911
/*
1012
* Fixed 0.5 second sampling window.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package datadog.trace.api.sampling;
2+
3+
import java.time.Duration;
4+
import java.time.temporal.ChronoUnit;
5+
6+
public class PerRecordingRateLimiter {
7+
8+
private final AdaptiveSampler sampler;
9+
10+
public PerRecordingRateLimiter(
11+
Duration windowDuration, int limit, int recordingLength) {
12+
int lookback = samplingWindowsPerRecording(recordingLength, windowDuration);
13+
int samplesPerWindow = limit / samplingWindowsPerRecording(recordingLength, windowDuration);
14+
sampler = new AdaptiveSampler(windowDuration, samplesPerWindow, lookback, 16, false);
15+
}
16+
17+
public void start() {
18+
sampler.start();
19+
}
20+
21+
public boolean permit() {
22+
return sampler.sample();
23+
}
24+
25+
public static int samplingWindowsPerRecording(
26+
long uploadPeriodSeconds, Duration samplingWindow) {
27+
/*
28+
* Java8 doesn't have dividedBy#Duration so we have to implement poor man's version.
29+
* None of these durations should be big enough to warrant dealing with bigints.
30+
* We also do not care about nanoseconds here.
31+
*/
32+
return (int)
33+
Math.min(
34+
Duration.of(uploadPeriodSeconds, ChronoUnit.SECONDS).toMillis()
35+
/ samplingWindow.toMillis(),
36+
Integer.MAX_VALUE);
37+
}
38+
}

0 commit comments

Comments
 (0)