Skip to content

Commit 3673735

Browse files
committed
chaos: fix stale-racer wake timing and stopGracefully timeout budget
Include ACTIVE_PHASE_MILLIS in STALE_RACER_SLEEP_MILLIS so racers wake as the next active phase begins instead of ~3s early. Bound stopGracefully's total wait to the caller's timeout via a shared deadline instead of giving each join/tryAcquire the full budget independently.
1 parent e1dd0fb commit 3673735

1 file changed

Lines changed: 13 additions & 6 deletions

File tree

ddprof-stresstest/src/chaos/java/com/datadoghq/profiler/chaos/VirtualThreadContextCascadeAntagonist.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public final class VirtualThreadContextCascadeAntagonist implements Antagonist {
112112
// carriers actually exit before the stale-buffer racers spawned in the burst wake back up.
113113
private static final long ACTIVE_PHASE_MILLIS = 8_000L;
114114
private static final long QUIET_PHASE_MILLIS = 40_000L;
115-
private static final long STALE_RACER_SLEEP_MILLIS = QUIET_PHASE_MILLIS + 5_000L;
115+
private static final long STALE_RACER_SLEEP_MILLIS = ACTIVE_PHASE_MILLIS + QUIET_PHASE_MILLIS + 5_000L;
116116
private static final int STALE_RACER_BATCH = 16;
117117
private static final int MAX_STALE_RACERS = 256;
118118

@@ -176,36 +176,43 @@ public void start() {
176176
@Override
177177
public void stopGracefully(Duration timeout) {
178178
running = false;
179+
long deadlineNanos = System.nanoTime() + timeout.toNanos();
179180
try {
180-
driver.join(timeout.toMillis());
181+
driver.join(remainingMillis(deadlineNanos));
181182
} catch (InterruptedException e) {
182183
Thread.currentThread().interrupt();
183184
}
184185
try {
185-
pinningDriver.join(timeout.toMillis());
186+
pinningDriver.join(remainingMillis(deadlineNanos));
186187
} catch (InterruptedException e) {
187188
Thread.currentThread().interrupt();
188189
}
189190
// Best-effort drain of in-flight cascades so the JVM doesn't exit mid-fan-out.
190191
try {
191-
liveVthreads.tryAcquire(MAX_LIVE_VTHREADS, timeout.toMillis(), TimeUnit.MILLISECONDS);
192+
liveVthreads.tryAcquire(MAX_LIVE_VTHREADS, remainingMillis(deadlineNanos), TimeUnit.MILLISECONDS);
192193
} catch (InterruptedException e) {
193194
Thread.currentThread().interrupt();
194195
}
195196
try {
196-
livePinVthreads.tryAcquire(MAX_PIN_VTHREADS, timeout.toMillis(), TimeUnit.MILLISECONDS);
197+
livePinVthreads.tryAcquire(MAX_PIN_VTHREADS, remainingMillis(deadlineNanos), TimeUnit.MILLISECONDS);
197198
} catch (InterruptedException e) {
198199
Thread.currentThread().interrupt();
199200
}
200201
// Stale-buffer racers sleep well past stopGracefully's own timeout budget, so this is
201202
// best-effort only — outstanding racers are daemon threads and die with the JVM.
202203
try {
203-
liveStaleRacers.tryAcquire(MAX_STALE_RACERS, timeout.toMillis(), TimeUnit.MILLISECONDS);
204+
liveStaleRacers.tryAcquire(MAX_STALE_RACERS, remainingMillis(deadlineNanos), TimeUnit.MILLISECONDS);
204205
} catch (InterruptedException e) {
205206
Thread.currentThread().interrupt();
206207
}
207208
}
208209

210+
/** Milliseconds remaining until {@code deadlineNanos}, clamped to zero (never negative). */
211+
private static long remainingMillis(long deadlineNanos) {
212+
long remainingNanos = deadlineNanos - System.nanoTime();
213+
return remainingNanos <= 0L ? 0L : TimeUnit.NANOSECONDS.toMillis(remainingNanos);
214+
}
215+
209216
/**
210217
* Independently pins short-lived virtual threads to their carrier and releases them again,
211218
* forcing the scheduler to grow and shrink its compensating carrier pool while cascade nodes

0 commit comments

Comments
 (0)