GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — [profiler] Wait for cytoscape to draw before the pixel tests read the canvas by Karakatiza666 · Pull Request #7840 · feldera/feldera Conversation
|
| Harness | Late frames | Normal |
|---|---|---|
| old | 2 and 5 of 150 failed (2 runs) | |
| new | 150/150 pass (3 runs) | 150/150 pass (3 runs) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
… canvas `settle()` waited a fixed 150 ms, but cytoscape draws on animation frames. On a busy CI runner a frame can come later, and the pixel probes in diagramShadows and diagramText read the previous frame. `settle()` now also waits until a frame passes without a cytoscape `render` event. Fixes #7767 Co-Authored-By: Claude Opus 5.5 <[email protected]>
| // Cytoscape requests its frame callback during the previous frame, so its callback runs before | ||
| // this one. Cytoscape emits `render` after each draw, so a frame without `render` had no draw | ||
| // pending. | ||
| let hasDrawn = false | ||
| const onRender = () => { | ||
| hasDrawn = true | ||
| } | ||
| mountedCy.on('render', onRender) | ||
| do { | ||
| hasDrawn = false | ||
| await nextFrame() | ||
| } while (hasDrawn) | ||
| mountedCy.off('render', onRender) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
bug (medium): a frame with no render does not mean no draw is pending. Cytoscape's texture caches dequeue in beforeRenderCallbacks on frames that do not draw. They then request the redraw through a lodash debounce set to deqRedrawThreshold, which is 50–100 ms (setupDequeueing in cytoscape 3.33.1). The LayeredTextureCache works the same way.
I tested this. A probe stayed inside settle() for 400 ms after the loop exited and counted render events. I also delayed animation frames by a random 0–400 ms, the same way your PR testing did.
node text > draws the text itself… and the selection glow > paints nothing…. Wrapping renderer().redraw showed the callers were trailingEdge (debounce) → LayeredTextureCache, plus some BRp.notify.The tests still passed, so these redraws seem to be mostly texture refinement. Still, the comment states something that is not true, and the probes can still read a frame that is about to change. One fix is to also require a quiet stretch longer than the debounce:
let last = performance.now() const onRender = () => { last = performance.now() } mountedCy.on('render', onRender) // A frame with no draw is not enough: the texture caches ask for their redraw // from a 50-100 ms debounce, so also wait out that delay. let frames = 0 do { frames++ await nextFrame() } while (frames < 2 || performance.now() - last < 150) mountedCy.off('render', onRender)
Also consider try/finally around the off, and resetting mountedCy in cleanup, so a later settle() does not wait on a removed instance.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Agreed, fixed in 0f12d9c. I traced the late draws to the same chain: element texture refinement, then scheduleElementRefinement (50 ms), then the LayeredTextureCache dequeue and its redraw debounce (50 ms).
I did not use the suggested condition (150 ms since the last render). With late frames it can still exit too early: if the last draw was 400 ms ago and the next frame starts a refinement, the loop exits and the debounced redraw comes after. A refinement step only advances in a frame, so the condition counts frames:
settle() returns after 3 frames without a draw, each at least 120 ms after the one before (longer than the longest debounce).off is in finally, and cleanup() resets mountedCy.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Review of the test-harness-only fix for #7767
The other gates (docs, deps, breaking changes, unsafe, CI) don't apply to a test-only change. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Addressed the review in 0f12d9c:
Cost: the browser suite takes about 28 s instead of 20 s locally, because each |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
0f12d9c to
a721263
Compare
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Flaky pixel-comparison tests in profiler-layout (diagramShadows/diagramText)
There was an error while loading. Please reload this page.