Repository navigation
feat(cli): expose timing.forward_model (op_level | fpm) on predict and recommend [AIC-1926] - #126
Conversation
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…ig [AIC-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…IC-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…s [AIC-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…IC-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…C-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…n gate accurately [AIC-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
… [AIC-1926] Signed-off-by: Yiming Liu <yimingl@nvidia.com>
jasonqinzhou
left a comment
There was a problem hiding this comment.
APPROVE · 9.2/10 · medium confidence
What this PR does
This PR exposes per-worker op-level versus whole-forward FPM timing selection in the unified predict and recommend configuration, threads that choice through compilation and sweeper candidate generation, and records it in performance-model provenance.
The change is carefully carried across both predict and recommend paths, and the tests distinguish plumbing from accuracy while explicitly proving that an uncovered FPM identity fails closed instead of falling back silently.
Why this score
The 9.2 score reflects an approval-quality Codex pass with clean targeted tests and CI lint, but the packet recommendation is BLOCKED because the required independent Fable model was not observed. No comments should be posted from this packet; the unverified fallback output is retained only as non-canonical evidence.
Summary
Adds
engine.workers.<role>.timing.forward_model: op_level | fpmto the unifiedaisimulate predictandaisimulate recommendYAML so the AIC forward-pass model can be selected per worker role.op_levelis the default and today's behavior;fpmreplays whole-forward (FPM) latency from a collected cell. Until now FPM timing was reachable only through the deprecated compatibility command (aiconfigurator cli estimate --forward-model fpm) or by compiling the YAML from Python and injecting a hand-builttiming_modelblock into the replay spec, and the migration guide listed--forward-modelas having no unified-CLI mapping. Linear: AIC-1926.Design
The runtime already supports FPM: the Rust
AicTimingConfigacceptsforward_modeland passes it tocompile_engine. This PR only adds the front end, and no Rust code changes.config/engine.py):TimingConfig.forward_model: Literal["op_level", "fpm"] = "op_level", shared by predict and recommend;fpmis rejected unlesstiming.typeisdefault.compiler.py,runner.py): the compiler emits the rank fieldaic_forward_modelonly when the value isfpm, so op_level replay specs are byte-identical to before; the runner's AIC alias table folds it into thetiming_model.configit already synthesizes and validates the value. Per-workerperformance_model_metadatanow recordsforward_model(op_levelorfpm) for provenance.recommend.py,sweeper/config.py,sweeper/sample.py,sweeper/deploy.py): the per-role value lowers into three pinnedSearchSpacefields (agg_forward_model,prefill_forward_model,decode_forward_model, defaultop_level, validated), travels throughunroll_sample, anddeploy.pyemits the same rank field and metadata. Every emitted candidate YAML spells outtiming.forward_model, consistent with the normalization that already materializes every other schema default.PerfDataNotAvailableError; the Sweeper records it as a failed candidate (reason categoryreplay_runtime). There is no silent fallback toop_level. A fallback policy is out of scope here (AIC-1770 / refactor(perfmodel): unify estimator construction and CLI policies [AIC-1770] #13). Infpmmode with default capacity, the KV capacity is also capped to the cell's collected decode-KV ceiling (existing Rust behavior, now documented).docs/cli/design.md(field table row + paragraph),docs/cli/migrate-from-aiconfigurator.md(--forward-modelnow maps to the new field;--database-mode,--transfer-policy,--systems-pathsstay unmapped),docs/sweeper/configuration.md.Coexistence with #13 (AIC-1770)
#13 flattens a canonical
ForwardPassPerfModelConfiginto the RustAicTimingConfigviaserde(flatten), so the flatforward_modelkey this PR writes intotiming_model.configstays valid before and after it. #13 also adds a sweep-wideforward_modeltoSearchSpaceand builds the estimator config from it indeploy.py; the per-role fields here use different names, so there is no collision, but the merge must thread<role>_forward_modelinto the per-role estimator construction (otherwise the per-role value would be silently discarded). The intended shape after #13 is per-role fields defaulting to "inherit the sweep-wide value"; that is deliberately not pre-empted here against a draft. Expect textual conflicts insweeper/config.py,sweeper/deploy.py, their tests anddocs/sweeper/configuration.md.Version-slot note
The bundled FPM cells (
h200_sxm/vllm/0.25.1MiniMax-M2.7,b200_sxm/vllm/0.25.1GLM-5.2-NVFP4) are collected at backend versions outside the queryable version slots, and the Rust AIC provider enforces the slot gate at engine compile, so FPM replays on them needAIC_ALLOW_UNLISTED_VERSIONS=1. That is pre-existing behavior; the design doc now documents it as a transitional escape hatch (the variable is described inperf_database.pyas a transition aid slated for retirement). Follow-up worth its own issue: make FPM cells slot-queryable, or add an allow path to the RustAicTimingConfig, so the documented FPM path does not depend on it. The tests that replay FPM set the variable explicitly and nowhere else.Testing
tests/test_cli_config.py), compiler emission per role and metadata (tests/test_unified_traffic_runtime.py), runner alias, duplicate-configuration conflict and invalid value (tests/test_runner.py), Sweeper fields and deploy payload for agg/disagg/fixed timing (tests/sweeper/test_config.py,tests/sweeper/test_deploy.py), recommend lowering and candidate round trip (tests/test_cli_config.py).fpm; an uncovered identity (tp2) fails closed underfpmwhile the same shape replays underop_level(tests/test_unified_traffic_runtime.py).tests/e2e/configs/unified_cli/predict/fpm/01-minimax-m27-h200-tp4-fpm.yamlthroughpython -m aisimulate predict, once as written and once with--set …forward_model=op_level, both completing (kept outsidepredict/engine/because that directory's exact case list runs without the env var).aisimulate predict --set …forward_model=fpmat c16 gives median TPOT 16.26 ms / median TTFT 445.0 ms, matching the injection-driven run that was compared against InferenceX silicon.testssuite at head: 511 passed, 5 pre-existing skips;ruff checkas in CI: clean.Behavior changes to be aware of
performance_model_metadata[<role>]["config"]gains aforward_modelkey (two goldens updated); under fixed/polynomial timing it recordsop_level, matching the predict-side schema rule.aisimulate recommendcandidate YAML now carriestiming.forward_modelexplicitly (op_levelfor existing configurations), like the other schema defaults the candidate normalization already spells out.Out of scope / follow-ups
Fallback policy for uncovered cells,
database_mode/systems_paths/transfer_policyon the unified YAML (AIC-1770, #13), the compatibility command's deprecation message (it fires unconditionally and points at the archived repository's migration guide; separate fix).🤖 Generated with Claude Code