Skip to content

feat(perf): auto-build a genai bundle from a model id for --runtime winml-genai#1109

Merged
DingmaomaoBJTU merged 3 commits into
mainfrom
perf-autobuild-genai-bundle
Jul 14, 2026
Merged

feat(perf): auto-build a genai bundle from a model id for --runtime winml-genai#1109
DingmaomaoBJTU merged 3 commits into
mainfrom
perf-autobuild-genai-bundle

Conversation

@DingmaomaoBJTU

Copy link
Copy Markdown
Collaborator

What

winml perf -m <hf-model-id> --runtime winml-genai now auto-builds a genai bundle from a HuggingFace model id instead of requiring a prebuilt bundle directory.

Why

The winml runtime already auto-builds an ONNX from a model id on demand. The winml-genai runtime forced users to first run winml build ... --device npu --ep qnn and then point perf at the output directory. This mirrors the winml behavior so a bare model id "just works".

How

  • New _autobuild_genai_bundle helper: resolves the model family, looks up its genai-bundle recipe, and builds into the managed cache dir (get_model_dir(model)/genai-bundle), pinning ep=qnn / device=npu (genai bundles target the NPU HTP via QNN). A prior build is reused unless --rebuild / --ignore-cache forces a fresh one.
  • _run_genai_runtime now distinguishes inputs: a directory is used as-is (must contain genai_config.json), an .onnx path is rejected, anything else is treated as a model id and auto-built on demand.
  • When auto-built, the report path is derived from the model id (the cache dir name is not a meaningful slug).
  • Docs: perf.md and the qwen3-genai-bundle.md sample updated with the one-command flow.

Unblocks winml perf -m Qwen/Qwen3-0.6B --runtime winml-genai.

…inml-genai

winml perf -m <hf-model-id> --runtime winml-genai previously required a prebuilt
genai bundle directory. Mirror the winml runtime's on-the-fly build: when -m is a
model id (not a bundle dir), build a genai bundle into the managed cache
(ep=qnn/device=npu) and benchmark it, reusing a cached bundle unless
--rebuild/--ignore-cache forces a fresh one. A bundle directory is still used
as-is and an .onnx path is still rejected.
@DingmaomaoBJTU DingmaomaoBJTU requested a review from a team as a code owner July 14, 2026 08:23
The model-id genai auto-build wrote into the managed cache even under
--ignore-cache, collapsing --ignore-cache and --rebuild into one behavior --
unlike the winml runtime, where --ignore-cache builds in a throwaway temp dir
and leaves the cache untouched (as documented in perf.md).

Under --ignore-cache, build the auto-built bundle (and its component build
cache) in a throwaway temp dir tied to an ExitStack so it outlives the
benchmark and is removed after. --rebuild still overwrites the cached bundle;
a plain run still reuses it.

Also stop reporting --task/--precision/--rebuild/--ignore-cache as "ignored"
when a bundle is auto-built from a model id -- those flags drive the build. A
prebuilt bundle still ignores them all.

@xieofxie xieofxie left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Well-structured PR with clean logic, comprehensive test coverage, and good documentation. The auto-build pattern mirrors the existing winml runtime's on-the-fly behavior nicely. A few observations below (none blocking).

Key observations

  1. Input routing heuristic (perf.py:1912-1925): When a model string looks like a filesystem path (e.g. user typo'd a directory) but doesn't exist, is_dir() returns False and it falls into the auto-build branch. The resulting error is serviceable but could confuse users who clearly intended a local path. A cheap heuristic (check for path separators) could surface a friendlier "path does not exist" before attempting the HF lookup.

  2. Cache-hit integrity (perf.py:1836): The cache check keys solely on genai_config.json existing. A prior build interrupted mid-write could leave that file but an incomplete bundle. Either a lightweight sanity check (valid JSON + at least one .onnx) or a comment documenting why this is acceptable (GenaiSession will fail fast) would be helpful.

  3. --ep and _GENAI_AUTOBUILD_FLAGS (perf.py:1760): The auto-build pins ep=qnn, but "ep" is not in _GENAI_AUTOBUILD_FLAGS. If a user passes --ep qnn alongside a model id, it gets warned as "ignored" even though it's consistent. Not a bug (correct from the benchmark-routing angle) but could cause minor user confusion. Worth considering.

  4. Dense table row (perf.md:11): The --runtime description is quite long for a markdown table cell. Consider moving the detailed explanation below the table or to a subsection.

Positives

  • ExitStack pattern for temp-dir lifetime management is elegant
  • Test matrix is thorough: autobuild, cache-hit, rebuild, ignore-cache, warning suppression, recipe rejection
  • Good error messages with actionable hints (pass a prebuilt bundle directory)
  • Documentation tip box in the sample page is well-placed

Verdict: Approve — the concerns above are all minor/non-blocking.

On a genai auto-build cache hit, the bundle keyed by model id alone is
reused as-is, so --precision/--task are not applied to it. Suppress their
ignored-flags warning only when a fresh build actually ran; report them as
ignored on a cache hit so the drop is not silent. --rebuild/--ignore-cache
always force a build (never reuse), so they stay suppressed on any
auto-build. Adds a cache-hit warning test.
@DingmaomaoBJTU DingmaomaoBJTU merged commit 3f5e468 into main Jul 14, 2026
9 checks passed
@DingmaomaoBJTU DingmaomaoBJTU deleted the perf-autobuild-genai-bundle branch July 14, 2026 09:45
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.

3 participants