Execution — bi-11-scheduling

Steps extracted from CONCEPTS.md. Read the concepts first; this file is the doing.

Record results in observation.md; tick checkpoints in verification.md.


6. Lab

  1. Priority inversion experiment. Post work at several scheduler.postTask priorities plus setTimeout and MessageChannel. Register a click handler. Measure ordering and input delay under a synthetic main-thread load. Predict the ordering first.
  2. Yield-cost curve. Take a 200 ms computation. Chunk it yielding every 0.5/5/50 ms via MessageChannel, then via scheduler.yield(). Plot total time and p75 input delay. Find where each curve turns.
  3. rAF vs timer. Animate with both under load. Measure frame alignment and dropped frames.
  4. Continuation priority. Construct a case where MessageChannel yielding loses to unrelated tasks and scheduler.yield() does not. This is the experiment that proves why the API exists.
  5. Throttling. Measure timer behaviour in a hidden tab and a hidden cross-origin iframe.

Deliverable: the two plots from (2) and (4), plus a recommendation you would give a platform team about which yielding primitive to standardise on — including its failure mode.


7. Failure Lab

  1. Recursive queueMicrotask — freeze the tab. Confirm the debugger cannot break in cleanly, and explain why in terms of the checkpoint.
  2. Starve rendering with a chain of high-priority tasks. Find where anti-starvation kicks in.
  3. Write a long task that delays a click by >300 ms. Reduce it to <50 ms without making the total work faster. State exactly what you changed.

8. Debugging Exercise

  1. Perfetto with toplevel + blink + cc: identify task boundaries, the microtask checkpoint, and the rendering opportunity in one trace.
  2. Find a long task and attribute it to a task queue/source.
  3. Correlate a TRACE_EVENT name from the trace back to its source (bi-01, rung 3 → rung 1).
  4. Observe a frame that produced no rendering. Explain why not.