feat: EP registration + monitoring — subprocess isolation, structured failures, universal op-tracing dispatch, lazy CLI startup#1019
Conversation
|
Let’s exclude the .md files from this pr. |
|
please
Thanks |
… pass
Squashes 17 commits: the original 292043e2 unified-source EP refactor
plus 16 rounds of fact-check-driven fixes and cleanup.
## Original refactor (292043e2)
- Unified-source EP registration: PyPISource / NuGetSource / DirectorySource /
WinMLCatalogSource / MSIXPackageSource / BuiltinSource under one iter_eps()
interface. Built-ins synthesized last (lowest precedence per registry design).
- WinMLEPRegistry rewired: EP source-tag pinning via --ep <name>@<source>;
EP_DEVICE_SPECS as authoritative catalog with vendor+device preference order.
- WinMLSession redesign: WinMLEPDevice threaded through session builders;
auto_detect_device / auto_device unified across CLI entry points.
- Perf command rewrite: two Panels (Model + Device) at pre-bench; two-line
now%/avg% status; GPU utilization (bright_yellow) added to NPU+CPU chart.
- OpenVINOMonitor: reduced to CLI-refusal stub (Fix A — Intel plugin lacks
ORT_OPENVINO_PERF_COUNT). QNNMonitor unchanged.
- msix source-tag collapsed to single 'msix' (removed microsoft/workload split).
- sys.py: isolated_ep_register subprocess helper for truthful per-DLL metadata.
## P0 / P1 fixes (rounds 1 and 2 — post-fact-check)
- P0-A analyze/analyzer.py:681 lazy import of removed sysinfo.resolve_device.
- P0-B analyze/utils/ep_utils.py:82 lazy import of deleted sysinfo.device.
- P0-C models/auto.py composite dispatch NameError after ep_device collapse.
- T-01 widened: ep click callback annotation across 4 commands (perf/compile/
build/config) — tuple leak in compile.py fixed alongside.
- P1-D WinMLEPRegistry.__init__ propagates ORT init failure loudly instead
of silently synthesising an empty registry.
- P1-E EP_DEVICE_SPECS preference-order regression pins (DML deprioritized).
## Simplify pass (round 3 — post-verdicts)
Real bugs (test-first):
- B1 model_validator_manager device double-assignment fallback bug.
- B2 inference/engine.py: 3 loader paths passed device=/ep= to APIs requiring
ep_device — thread ep_device through.
- B3 WinMLCompositeModel.from_pretrained: TypeError on T5/Qwen3/Mu2 sub-model
construction — accept ep_device in signature, thread through sub-models.
- B6 WinMLCompositeModel.from_pretrained: silently dropped device kwarg —
forward into __init__.
Whole-module deletions (verified dead):
- optracing/ (pycache stumps only, code moved to session/monitor/).
- utils/optimum_loader.py, utils/hub_utils.py.
- export/htp/config_generator.py (imports non-existent inference/onnx_config/).
- analyze/utils/pattern_matching.py.
Dead API trim (verified zero-caller):
- EPCatalog.vendor_requirements_for, EPCatalog.all_dlls.
- run_basic_viewer (qnn/viewer.py, 52 lines).
- DeviceNotAvailableError, NotCompiledError exception classes.
- Two unreachable except NotImplementedError clauses in discover_all_eps.
- _split_op_event_id: dead 'name' field dropped; collapsed to str return.
Duplication consolidation (verbatim / drift-verified):
- perf.py: _open_ep_monitor_or_exit helper replaces 60-line copy-paste with
drifted warning strings ('on this system' vs 'ONNX benchmark').
- perf.py: _pre_bench_kwargs_from_ep_device helper for 6-field projection.
- build/hf.py + build/onnx.py stages [3]-[6] (~140 lines) consolidated into
build/common.py per the pre-existing FIXME.
- analyze OpenVINONPUChecker/QNNNPUChecker copy-paste: check_patterns.py
now re-imports from check_ops.py.
## Verification
- Full unit suite: 29 failed / 5128 passed (baseline 29 failed / 5156 passed
before deletions; zero new failures introduced).
- 43+ new regression pins across the P0/P1/simplify rounds.
- All modified files ruff clean.
- Analysis corpus under commit-analysis/<sha>/ documents every finding with
fact-check verdicts (Confirmed / Partially / Refuted).
d242cd6 to
cc7a665
Compare
Runnable CLI verification against the squash commit. Every command / flag / expected-output snippet verified against actual src + live CLI output over two parallel-agent runs (39/39 PASS, 0 regressions). Covers: sys, perf, compile, build, config, analyze, eval, hub, inspect, optimize, quantize, export, expand_rules. Documents disabled commands (run, serve) and expected ORT native warnings as non-regressions. Includes ENV triage table (8 rows), timing expectations table (7 rows), composite ONNX export downstream-bug classification, anti-pattern grep table for T-01 / B2 / B3 / B6 / P0-A / P0-B / D4 regression signatures.
E2E verification checklistRunnable verification protocol for this branch — see Verified on Intel/OpenVINO NPU host (author). Other platforms — please pick up the delta. Minimum smoke (~5 min with warm cache)uv run winml sys --format json
uv run winml perf -m microsoft/resnet-50 --device auto --ep auto --monitor
uv run winml perf -m ./convnext/model_opt_qdq.onnx --ep qnn --device npu --op-tracing basic
uv run winml perf -m t5-small --device cpuPlatforms wanted
How to classify failures
Anti-pattern grepEvery regression signature has a grep pattern in the doc's grep table. If you find Author's results (two runs, Intel host)
Raw command outputs under If you're picking up a platform
|
PR #1019 E2E Verification PlanBranch: Context / why this doc existsPR #1019's own "Test plan" checklist references a three-commit chain A prior manual check on High-level goalIndependently re-verify every item in PR #1019's Test plan checklist High-level passing criteriaAll of the following must be true to close this verification:
TasksEach task is independent and can be picked up in any order, but Task 1 Task 1 — Full unit test suite baselineGoal: establish the true current pass/fail/skip counts on Command: Pass criteria:
Verdict recorded as: PASS if all failures fall into a known Task 2 — OpenVINO monitor unit testsGoal: confirm the second op-tracing monitor implementation Command: Pass criteria: all tests pass (PR claims 27). If the count differs, Task 3 — Perf/op-tracing dispatch unit testsGoal: confirm Command: Pass criteria: all tests pass (PR claims 45, 7 new for dispatch). Task 4 — CLI cold-start performanceGoal: confirm Commands: then verify Pass criteria: Task 5 —
|
Summary
Six capability areas landed across 3 commits. Op-tracing is one; the others are load-bearing infrastructure the CLI relies on.
1. EP registration hardening (
commands/sys.py)isolated_ep_registerruns each filesystem-backed EP registration in a fresh Python subprocess so Windows' process-wide, base-name-keyed loaded-modules table can't leak the first-loadedplugin_impl.dll's metadata into every subsequent call.ThreadPoolExecutor(max_workers=4)parallelizes the fleet — 14 s → ~9 s on a 7-EP box. Nested_worker()function shipped viainspect.getsourcetopython -c;subprocess.run(timeout=...)cleanly terminates hung children.2. Structured EP failure attribution (
session/ep_device.py)WinMLEPRegistrationFailedupgraded from an opaque message wrapper to a structured exception carrying.code,.reason,.dll_path,.fallback_version, all parsed at construction. Reason table covers Win32 error codes 2, 5, 126, 127, 193, 1114; unknown codes get a generic fallback.fallback_versionreads the DLL's PEVS_VERSIONINFOviapywin32so[failed]rows still surface a truthful version even when ORT never loaded the binary.3. EP registry API surface (
session/ep_registry.py)WinMLEP.arg0(identifier forunregister_execution_provider_library),WinMLEP.to_dict()serializingplugin_version+ per-devicedevice_factsso Architecture/Driver rows survive the subprocess boundary,WinMLEPRegistry.unregister_ep()for the register → snapshot → unregister cadence.4. Op-tracing monitor extension (
session/monitor/openvino_monitor.pyNEW +commands/perf.py)Second op-tracing monitor implementation. Universal
_resolve_ep_monitordispatch: auto-selects by device (NPU/auto → try monitor A, fall back to B; GPU → B), explicit--ephonored,--op-tracing detailrejected when the resolved EP has no detail surface. Enabled via ORT env var +load_configprovider option; per-inference CSV flush (not per-session-destroy); env var save/restore in__enter__/__exit__so we never leak monitor state.5. CLI cold-start perf (
transformers_compat.pyNEW,_transformers_compat.pydeleted)Prior state eagerly imported the transformers 5.x compat shim from
winml.modelkit.__init__, dragging transformers (~10 s cold) into every invocation — includingwinml --help. That defeated the PEP 562 lazy dispatch the package already had. Fix: wrap the shim body ininstall(), register_OptimumImportHookatsys.meta_path[0]that firesinstall()the first time anything importsoptimum.*. Lightweight commands never fire the hook; heavy commands fire it once, transparently.install()sets the guard flag at entry (prevents recursion wheninstall()itself imports optimum) and rolls it back on any exception.winml --helpcold path: 277 ms with transformers NOT insys.modules.6. Test coverage gap closed
tests/cli/was outside the CI matrix and never caught the transformers regression that landed with the transformers-5 upgrade. Moved totests/unit/cli/pertests/CLAUDE.mdlayout rule, addedcligroup to.github/workflows/modelkit-ci.ymlmatrix, deleted the 460-line duplicate at repo root, addedTestWallClockguardrail (winml --help< 8 s in a fresh subprocess).Commits
e6be7659— feat(session): op-tracing monitor for second EP + universal dispatch0e2b5f05— perf(cli): auto-fire transformers 5.x compat shim via sys.meta_path hook9a8993f4— feat(session): isolate EP registration in fresh subprocesses for truthful per-DLL metadataPre-existing baseline failures (out of scope, reproduce on
15861f75)_LAZY_IMPORTS[winml.modelkit.onnx]drift —onnx/__init__.pylacks the PEP 562 dispatch pattern other subpackages already useTestSysCommandAttributeError: 'list' object has no attribute 'items'shape drift in sys command test fixturesBoth categories reproduce on
15861f75before any commit on this branch and are explicitly declared out of scope in commit0e2b5f05's message.Test plan
uv run pytest tests/unit/ tests/unit/cli/ --timeout=60— expect 1149 passed, 6 pre-existing baseline failures, 8 legit skipsuv run pytest tests/unit/session/monitor/test_openvino_monitor.py— 27 tests, all greenuv run pytest tests/unit/commands/test_perf_optracing.py— 45 tests (7 new for op-tracing dispatch), all greenuv run winml --help— sub-second,'transformers' not in sys.modules$env:WINMLCLI_EP_PATH="...\x64\Release"; uv run winml sys— 5 truthful OpenVINO row versions surface + Architecture/Driver rendered for NPU/GPU +[failed]rows show compact Win32 reason + PE fallback versionuv run winml perf -m microsoft/resnet-50— exit 0, latency ~2.5 ms, throughput > 300 samples/secuv run winml perf -m microsoft/resnet-50 --monitor— HW monitor renders, no monitor/EP errorsuv run winml perf --help—--op-tracinghelp text mentions "Auto-selects the monitor for the chosen EP" (no vendor-specific dispatch language)