Skip to content

perf(runner)!: persistent runner loop and latest-value limit mailbox - #128

Closed
greenhat616 wants to merge 3 commits into
perf/event-loop-3-quick-winsfrom
perf/event-loop-4-runner-loop
Closed

greenhat616 wants to merge 3 commits into
perf/event-loop-3-quick-winsfrom
perf/event-loop-4-runner-loop

Conversation

@greenhat616

Copy link
Copy Markdown
Owner

Part 4/6. Stacked on part 3.

  • Runner split into control.rs and run_loop/{stream,emit,drain}.rs (pure move).
  • The runner is a state machine polled in place instead of rebuilding a select_biased! per event: -13..-24% time per frame, 2.8 instead of 6.7 allocations per 32 KiB frame (interleaved A/B).
  • BREAKING: manager limits go through a lock-free latest-value mailbox, so any number of limits can reach a connecting runner. TaskRunnerBuilder fields are private; RunnerManager, RunnerRegistration, ControlSender, ControlReceiver are no longer exported.

A pure move: `run` and `run_inner` go to `run_loop.rs`, buffering to
`run_loop/stream.rs`, pushing to `run_loop/emit.rs`, draining to
`run_loop/drain.rs`, `apply_control` and the control channel aliases to
`control.rs`, and the tests to `tests.rs`. Function bodies are unchanged
apart from visibility and formatting.
…ures

Each event of the runner rebuilt its cancellation, control, idle and push
futures inside a `select_biased!`. The runner is now a state machine
(publishing `Started`, streaming, draining, publishing `Stopped`) whose
sources live as long as the run; each phase polls them in its documented
priority order. Pushes use `poll_ready` and `try_push` on a staged frame,
so no future borrows the data sender.

Measured against the plain move, interleaved: 13-24% less time per frame
and 2.8 instead of 6.7 allocations per 32 KiB frame; setup, cancellation
latency and eight concurrent runners are within noise.
The runner manager sent each limit through a bounded channel of 8 that a
connecting runner does not read, so repeated splits could fill it. A
manager only ever lowers a runner's limit, so it now sends limits through
a lock-free single-slot mailbox: a newer limit replaces an unread one and
the runner reads only the latest. A runner built with the public
`TaskRunnerBuilder::control_signal` still applies every signal in order.

BREAKING CHANGE: `TaskRunnerBuilder` fields are private; use its setters.
`bolt_load::task::instance` no longer exports `RunnerManager`,
`RunnerRegistration`, `ControlSender` and `ControlReceiver`, which only the
concurrent task used.
@greenhat616
greenhat616 added this pull request to stack #131 October 15, 2026 10:49
@greenhat616
greenhat616 deleted the branch perf/event-loop-3-quick-wins October 16, 2026 01:09
@greenhat616

Copy link
Copy Markdown
Owner Author

Superseded by the finer-grained stack #132–#144 (one kind of change per PR). The final tree is identical.

@greenhat616
greenhat616 deleted the perf/event-loop-4-runner-loop branch October 16, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant