Skip to content

Commit 47685a9

Browse files
authored
fix(viewer): discard open polls at trace end instead of closing them (#194) (#208)
When a trace segment rotates with PollStart as the last event, the viewer was closing the open poll span at maxTs, creating a phantom long poll. Now open polls are simply discarded — only polls with a matching PollEnd are kept. The Rust analysis code (detect_long_polls) was already correct.
1 parent a269d09 commit 47685a9

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

dial9-viewer/ui/test_trace_analysis.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,28 @@ async function main() {
367367
pass("buildFgData returns null for empty samples");
368368
}
369369

370+
// ── Regression: open PollStart at trace end must not create phantom poll (#194) ──
371+
372+
function testOpenPollStartDiscarded() {
373+
// Simulate a rotated segment where PollStart is the last event (no PollEnd).
374+
const syntheticEvents = [
375+
{ eventType: EVENT_TYPES.PollStart, timestamp: 1000, workerId: 0, taskId: 1, spawnLocId: null, spawnLoc: null, localQueue: 0 },
376+
{ eventType: EVENT_TYPES.PollEnd, timestamp: 2000, workerId: 0 },
377+
// This PollStart has no matching PollEnd — file rotated
378+
{ eventType: EVENT_TYPES.PollStart, timestamp: 3000, workerId: 0, taskId: 2, spawnLocId: null, spawnLoc: null, localQueue: 0 },
379+
];
380+
const syntheticMaxTs = 1_000_000; // 1ms later — would create a huge phantom poll
381+
const result = buildWorkerSpans(syntheticEvents, [0], syntheticMaxTs);
382+
const polls = result.workerSpans[0].polls;
383+
if (polls.length !== 1) fail(`Expected 1 poll, got ${polls.length} — open PollStart was not discarded`);
384+
if (polls[0].start !== 1000 || polls[0].end !== 2000) fail(`Unexpected poll range`);
385+
pass("Open PollStart at trace end is discarded (no phantom long poll)");
386+
}
387+
370388
// ── Run all tests ──
371389

372390
console.log("\nbuildWorkerSpans:");
391+
testOpenPollStartDiscarded();
373392
testPollsHaveValidRange();
374393
testNoOverlappingPolls();
375394
testActiveRatiosInRange();

dial9-viewer/ui/trace_analysis.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,10 @@
145145
}
146146
}
147147

148-
// Close any open spans at trace end
148+
// Close any open park spans at trace end.
149+
// Open polls are discarded: a PollStart without a matching PollEnd
150+
// means the segment rotated mid-poll, not that the poll was long (#194).
149151
for (const w of workerIds) {
150-
if (openPoll[w] != null)
151-
workerSpans[w].polls.push({ start: openPoll[w], end: maxTs });
152152
if (openPark[w] != null)
153153
workerSpans[w].parks.push({ start: openPark[w], end: maxTs });
154154
}

0 commit comments

Comments
 (0)