Skip to content

CORE-121: run async nodes' ancestor cones first - #101

Open
LawlAoux wants to merge 2 commits into
masterfrom
CORE-121-cone-first-node-order
Open

LawlAoux wants to merge 2 commits into
masterfrom
CORE-121-cone-first-node-order

Conversation

@LawlAoux

Copy link
Copy Markdown
Contributor

Summary

Order the nodes so that every async node (an LLM or HTTP call) runs as early as its inputs allow: each async node's ancestor cone first, smallest cone first, then the node, then everything else.

  • computation_graph/run.py: _toposort_nodes is split into _node_to_dependencies (the transposed edge map), _layered_order (the existing toposort layers with async nodes first inside each layer) and a new _io_cones_first pass over that order. _ancestors is a plain reverse walk per async node. Computed once at build time; the runner is unchanged.
  • computation_graph/graph_test.py: test_toposort_runs_async_ancestor_cones_first, two graphs: an async node three hops deep must precede unrelated shallow nodes, and a deep async node with a 2-node cone must precede a shallow one with a 3-node cone. Both also assert the result is a topological order of every edge.

Why: toposort puts a node in the layer given by its longest input chain, and layer k runs after every node of the layers below k in the whole graph, needed or not. On atlantic the routing classifier's node sits in layer 17 of 506 (its should_run input is 16 hops deep through the FAQ trigger and a feature flag keyed by the caller's phone number), so 9,098 nodes (57%) run before it although its ancestor cone is 100 nodes. Louisiana: layer 11–17, 50%, cone 100. With cones first the classifier is reached after 6% (atlantic) / 4% (louisiana) of the nodes, and the options classifier moves from 63% to 11%.

The order only matters when tasks start at creation: nlu-runtime MR !9802 sets asyncio.eager_task_factory on the serving loop (with the default factory the request waits for the runner loop to end regardless of order). Independent of #91: this touches only the toposort, #91 only the executors.

Benchmark

Network-free harness from nlu-runtime (scripts/perf_baseline.py: in-process model endpoints, LLM stubbed, DNS disabled), one bot per process, 1 warm-up + N=5 measured conversations, connect + greet + 4 utterances, master (78) vs this branch back to back, both legs with the eager task factory (PERF_EAGER_TASKS=1), nlu code fixed at master ff3701382c. Two passes: the stub returns instantly, and the stub sleeps 800 ms to stand in for the model. Laptop on battery with Low Power Mode on, so read percentages and deltas, not absolute milliseconds.

When the classifier's LLM call leaves (ms after turn start, p50):

call atlantic louisiana
custom-intent classifier (route turn) 254 → 39 ms 347 → 54 ms
options classifier ("yes" turn) 440 → 118 ms

Turn walls with the instant stub: every turn within ±2% on both bots (the reorder itself is free). With the 800 ms stub:

turn atlantic p50 louisiana p50
route: schedule 1230 → 1023 ms (−17%) 1533 → 1238 ms (−19%)
"yes" (options classifier) 480 → 482 ms 1317 → 982 ms (−25%)
connect, greet, name, agent ±2% ±2%

The saving equals the CPU that used to run before the request and now overlaps the wait. Min moves with p50, bot texts identical on all turns of both passes, 0 errors, builds unchanged. Test suite: 65 passed.

Jira

CORE-121

yoni17 added 2 commits September 24, 2026 15:54
toposort layers a node by its longest input chain, and a layer runs
after every node of the layers below it in the whole graph, needed or
not. On atlantic the routing classifier sits in layer 17 of 506, so
9,098 nodes (57%) ran before it although its ancestor cone is 100 nodes.
Emit each async node's cone first (smallest cone first), then the node,
then everything else; a cone is closed under inputs, so the result is
still a topological order.

With eager tasks the classifier request leaves at 39 ms instead of
254 ms (atlantic) and 54 instead of 347 ms (louisiana); with an 800 ms
model wait the routing turn is 17-19% shorter, walls otherwise unchanged
and bot texts identical.
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