perf(planning): yield between asynchronous slices without a timer
Each slice of the asynchronous adapter waited for a zero-delay timer: about 1.1 ms in Bun, and at least 4 ms in browsers once timers nest. Browsers now yield through a message-channel task. Bun runs port messages ahead of timers and incoming worker messages, which starved cancellation and heartbeats, so it yields with setImmediate. Both still let queued cancellation and heartbeat tasks run between slices. Part of #302. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2fcba758c8
commit
b7ec411c92
3 files changed
+55
-9
No files matched your search
@@ -59,3 +59,33 @@ reconciliation; afterwards retention took 0.26 seconds.
|
||||
|
||||
The typed-obligations difference is run-to-run noise; its retention cost was
|
||||
22 milliseconds.
|
||||
|
||||
### Yield between asynchronous slices without a timer
|
||||
|
||||
The asynchronous adapter yields roughly every eight milliseconds. Each yield
|
||||
waited for a zero-delay timer: about 1.1 ms in Bun, and at least 4 ms in
|
||||
browsers once timers nest. Browsers now yield through a message-channel task.
|
||||
Bun runs port messages ahead of timers and incoming worker messages, so a
|
||||
message-channel yield there kept cancellation and the heartbeat from running
|
||||
until the calculation ended. Bun therefore yields with `setImmediate`, which
|
||||
costs about 0.01 ms and lets both run between slices.
|
||||
|
||||
| Scenario | Before (s) | After (s) |
|
||||
| --------------------------- | ---------: | --------: |
|
||||
| representative year | 0.37 | 0.31 |
|
||||
| typed obligations | 4.74 | 4.02 |
|
||||
| chained earned entitlements | 0.02 | 0.01 |
|
||||
| deliberate conflict | 0.01 | 0.00 |
|
||||
| loaded year | 53.80 | 46.90 |
|
||||
| two years | 1.23 | 1.04 |
|
||||
| three years | 3.86 | 3.21 |
|
||||
|
||||
The browser path was checked in headless Chromium 149 on the same machine, in a
|
||||
dedicated worker with a 50 ms heartbeat timer, running the bundled core before
|
||||
and after this step, alternating, twice each. The `three years` calculation took
|
||||
3.92 and 3.89 seconds before and 2.70 and 2.66 seconds after; `representative
|
||||
year` took 0.51 and 0.45 seconds before and 0.30 seconds after. The heartbeat's
|
||||
largest gap stayed between 58 and 67 ms in every run. Cancelling `three years`
|
||||
one second after the request returned the retained plan 3.9 to 4.0 ms after the
|
||||
cancel message reached the worker, against 7.2 to 8.7 ms before. This is desktop
|
||||
evidence, not a reference-phone measurement.
|
||||
Reference in new issue
Block a user