Repository navigation
Cosmos3-edge PR 4: a staged pre-plan only promotes into the step it was planned for - #295
Conversation
111d726 to
73face8
Compare
There was a problem hiding this comment.
The guard looks good and is correct to have, but unless I'm missing something, the worker loop is not intended to spuriously schedule other batches while the preplan is active. The speculative step always runs unless there is an admit failure, other error, or prepare_inputs returns all None.
Where I think the gap is that we skip rids if nevermind, this is handled by prepare_inputs returns None (which cosmos does if it's the last step of a batch, and I believe the engine's exec does not reset preplan in the case that all requests have been dropped.preplan_is_stale.
Some potential places it could be (?):
_handle_main_loop_errornever clears preplan, and also doesn't drain theplan_future._execute_on_gpu_thread'sfinallyblock doesn't clear preplan either
| if self._staged is None or step.ctx.is_preplan: | ||
| return | ||
| if self._staged != self._step_key(step): | ||
| logger.debug( |
There was a problem hiding this comment.
I'd change this to a logger.warning; it something that shouldn't be the typical path
There was a problem hiding this comment.
Done (1545386). It also names the staged step and the one that displaced it, rows included.
73face8 to
a134ffd
Compare
|
Looked at both places. On where the 09-17 stale pre-plan came from: the log we have shows a one-row decode pre-plan displaced by a five-row decode step of the same node, but I could not pin down which path armed it. With the warning naming both steps, the next occurrence will say. |
Fixes two crashes and a silent-corruption path in the speculative pre-plan, found while running concurrent Cosmos3-Edge reasoner requests.
The plan thread pre-plans a node's speculated next step while the current one runs. If the scheduler then dispatches a different batch on that node first (a new request's eager prefill while a decode step sits pre-planned), the pre-planning resources promoted the staged plan into the wrong step.
SamplerResource.plandereferencedctx.slot_lease.sloton the unleased step and took the worker main loop down ('NoneType' object has no attribute 'slot'), killing every in-flight request.KVManager.admit/planwould have handed the staged request's reserved pages and cached plan to the other step's segments.FlashInferManager.plan(and likewise the position and cross-attention managers) promote whatever is staged whenplanis next called, so attention ran with wrappers laid out for the other step's rows (q implies q_len_per_req=5 but plan() used 1). With equal row counts it would have attended over the other request's pages without any error.The guard now lives in
StepRunner, the one place that sees the whole step.pre_planrecords what it staged (walk, padded rows, lease slot, capture key, every resource's segments), andadmit/planclear the stage on every resource before a different step proceeds.Engine.reset_pre_plan_for_batchgoes through the same call. The KV and sampler checks stay as a second line of defense, and the pre-planned step itself just plans inline when its turn comes.Tests in
test/modular/test_preplan_guard.py(CPU). With the realKVManager, a foreign step admits and plans on its own pages while a pre-plan is staged and the staged plan is dropped, and a pre-plan still promotes into its own step. With aStepRunnerover two blindly-promoting fake resources, a foreign step (other rows, the same rows without their lease, another slot, another span) clears the stage on both, the staged step promotes on both, andclear_preplanreaches every resource. Also verified on H100 against the Cosmos3-Edge server with deterministic prompts at batch sizes 3 and 5 (padded to buckets 4 and 8), where every concurrent answer matched its sequential one byte for byte.ruffandtest/modularpass.