Repository navigation
Add Qwen3.8-Flash Engine qualification and benchmark tools - #2729
Draft
Tianlei Wu (tianleiwu) wants to merge 2 commits into
Draft
Tianlei Wu (tianleiwu) wants to merge 2 commits into
Tianlei Wu (tianleiwu) wants to merge 2 commits into
Conversation
Tianlei Wu (tianleiwu)
added a commit
that referenced
this pull request
Oct 14, 2026
…th auxiliary sessions (#2725) ## Description Adds `session_options.custom_ops_libraries`, a list of custom-op libraries registered in order after the existing single `custom_ops_library`, and exports `InheritSessionOptionsFromParent` so components that create auxiliary sessions (for example MTP/draft heads) can inherit the decoder's providers, provider options, config entries and custom ops. Models whose graphs use several custom-op domains (fused attention, hyper-connection, GEMM and head ops shipped next to the model package) currently cannot name more than one library. This change is generic and has no dependency on any model type; it is the first step of the Qwen3.8-Flash static-graph backend series (see the end of this description), but stands alone and targets `main`. ## Summary of Changes | File | Change | |------|--------| | `src/config.h`, `src/config.cpp` | New `session_options.custom_ops_libraries` (JSON string array; scalar values such as `"custom_ops_libraries": "ops.so"` are rejected during parsing). Overlays append to `custom_ops_libraries` (and `[]` leaves existing entries unchanged). `InheritSessionOptionsFromParent` exposes the existing inheritance helper; `custom_ops_library` and `custom_ops_libraries` are inherited together when the child sets neither (note that `"custom_ops_libraries": []` leaves the vector empty and therefore still inherits from the parent unless `custom_ops_library` is set). | | `src/models/model.cpp` | `custom_ops_library` and then every `custom_ops_libraries` entry go through the same path-traversal and allow-list checks, with duplicate resolved paths registered once. All paths are validated against the allow-list before loading starts; validated libraries are then loaded and registered sequentially in order (so a later load/registration error can still leave earlier libraries registered on `session_options`). | | `test/CMakeLists.txt`, `test/cpp/engine/custom_ops_test_lib/custom_ops_test_lib.cpp`, `test/cpp/engine/custom_ops_libraries_tests.cpp` | Builds two small test custom-op shared libraries (`custom_ops_test_first` and `custom_ops_test_second`) and tests parsing/ordering, overlay rules, rejection of non-string entries and scalar values, inheritance (including `[]` and `CreateMtpDecoderConfig`), allow-list validation, and actual library loading, ordering, and deduplication. | ### Library Location Requirement Every entry in `custom_ops_library` and `custom_ops_libraries` must resolve to an existing file inside one of the allowed directories: 1. The model folder (alongside `genai_config.json`), 2. A registered Execution Provider (EP) library directory, or 3. The current working directory. Previously, an unresolved bare library name in `custom_ops_library` was passed directly to `RegisterCustomOpsLibrary` and could be resolved through the platform loader search path (`LD_LIBRARY_PATH` / `PATH`). Unresolved entries are now rejected before loading so the directory allow-list cannot be bypassed; users should place custom-op libraries in one of the allowed directories above (typically the model folder). ## Testing - CPU-only Release build (`-DUSE_CUDA=OFF`) on `main`: `engine_unit_tests` **929 passed, 0 failed, 2 skipped** (including all 9 tests in `CustomOpsLibrariesConfigTest`, which load real test custom-op shared libraries to verify registration, ordering, and deduplication). - `lintrunner`, `clang-format` (20.1.8) and `git diff --check` are clean. ## Motivation and Context Found while hosting a model that uses seven custom-op libraries. Registering them through one `custom_ops_library` entry was not possible, and auxiliary sessions did not inherit the decoder's custom ops, so head graphs failed to load without repeating the whole session configuration. This is the first PR of a stack that adds an Engine-hosted CUDA-graph MTP backend for Qwen3.8-Flash-Next (greedy only, one resident request, Linux/CUDA, no prefix cache). The follow-ups are drafts stacked on `kvaishnavi/qwen-38-flash-run`, so this commit is also carried as the first commit of the next PR (#2726) until this one merges. The stack: #2726 (CUDA data plane library) -> #2727 (model type and device engine) -> #2728 (Engine hosting) -> #2729 (qualification tools). ## Checklist - [x] Tests added/updated - [x] No breaking changes - [ ] Documentation updated (the option is described in the PR; no dedicated config documentation exists for `session_options` yet) --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261013/ga-b5-qwen38-qualification-tools
branch
from
October 15, 2026 04:48
c68aae8 to
4100b68
Compare
Tianlei Wu (tianleiwu)
added a commit
that referenced
this pull request
Oct 17, 2026
- Reject duplicate custom-op library basenames, nested --out paths inside input directories, and non-empty --out directories in build_package.py and build_package_engine_v12b.py.
- Enforce a minimum prefix agreement floor in engine_gate.py --prefill fast mode and compare delivered token prefixes plus EOS termination across all EOS_IDS without fabricating EOS_IDS[0].
- Add v12c-opt and v12d builder options to build_package_engine_v12b.py: --lm-head-quant {none,fp8,head_fp8}, --hc-quant {none,fp8}, --host-map-embed, --prefill-chunk, --fuse-dense-ops, MTP head HC block merging, and rotary/attn_consts/head_kv initializer deduplication.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261013/ga-b5-qwen38-qualification-tools
branch
from
October 17, 2026 19:36
4100b68 to
a772f95
Compare
Tianlei Wu (tianleiwu)
added a commit
that referenced
this pull request
Oct 19, 2026
- Reject duplicate custom-op library basenames, nested --out paths inside input directories, and non-empty --out directories in build_package.py and build_package_engine_v12b.py.
- Enforce a minimum prefix agreement floor in engine_gate.py --prefill fast mode and compare delivered token prefixes plus EOS termination across all EOS_IDS without fabricating EOS_IDS[0].
- Add v12c-opt and v12d builder options to build_package_engine_v12b.py: --lm-head-quant {none,fp8,head_fp8}, --hc-quant {none,fp8}, --host-map-embed, --prefill-chunk, --fuse-dense-ops, MTP head HC block merging, and rotary/attn_consts/head_kv initializer deduplication.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261013/ga-b5-qwen38-qualification-tools
branch
from
October 19, 2026 08:57
a772f95 to
52635f2
Compare
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261013/ga-b5-qwen38-qualification-tools
branch
from
October 30, 2026 05:13
52635f2 to
5f1fccf
Compare
Tianlei Wu (tianleiwu)
changed the base branch from
tlwu/20261013/ga-b4-qwen38-engine-host
to
main
October 30, 2026 05:22
2 of 3 tasks
This was referenced Oct 30, 2026
Contributor
Author
|
Re-cut and force-pushed ( |
Add tools/qwen38_graph with the first half of the scripts that drive a qwen38_flash_graph package through the public Engine API, and a README of the backend (build, external artifacts, package layout, the v12b stack, usage, limits). - qwen38_engine_util.py: CUDA EP registration, model loading with config overlays, natural-text prompt pools supplied by the caller (no hard-coded locations), and the run_turn/pump helpers the other scripts share. Registers the DLL directories on Windows. - smoke.py: minimal usage example. - bench_engine_mtp.py: vLLM-protocol decode benchmark with per-position acceptance histograms. - bench_ttft_engine.py: time to first token at several prompt lengths. - calibrate_qwen38_kv.py: per-channel INT8/FP8 KV-cache scale calibration. - run_with_ram_budget.py, test_ram_budget.py: bound the host expert cache, and optionally the whole command through a systemd scope, for QMoE-offload runs. The scripts depend only on this tree, on the package they are given and on the external artifacts the README lists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the scripts that qualify a qwen38_flash_graph package through the Engine API, and document them in the README. - engine_gate.py: greedy token-identity gate against a reference stream; a --no-mtp or --force-reject recording makes the gate MTP == no-MTP. The steps prefill must be identical. The fast prefill is tolerance level, so it must agree on the prompt length, the first token and an identical prefix of at least --min-fast-prefix tokens. Streams are compared as the delivered tokens plus the termination reason across all stop ids, without assuming the first stop id. - engine_behaviours.py: stop tokens, limits, stop strings, cancellation during prefill and decode, queueing, continuation, rewind, capability errors and speculative statistics. - engine_prompt_lengths.py: prompt length and dense chunk boundary check, run once per prefill mode and then compared. - mmlu_engine_eval.py, lcb_engine_eval.py: resumable MMLU-Pro 800 and LiveCodeBench v6 accuracy runs through the Engine, with the MTP == no-MTP stream check for MMLU-Pro and sandboxed grading with a paired McNemar comparison for LiveCodeBench. - test_plane_kernels.py: kernel-level tests of the fast prefill kernels of the plane library against the research implementations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
force-pushed
the
tlwu/20261013/ga-b5-qwen38-qualification-tools
branch
from
October 30, 2026 05:45
5f1fccf to
8c2f4a1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the scripts that qualify a
qwen38_flash_graphpackage through the public Engine API (og.Engine/og.Request), and a README of the backend (build, external artifacts, package layout, theSpeculativePrefixCommitcontract of the rc4/rc5 DFlash2 packages, usage, scripts, limits).The scripts depend only on this tree, on the package they are given and on the external artifacts the README lists. The research helper modules that the MMLU-Pro and LiveCodeBench drivers import (
eval_lib,eval_mcq_genai) are not in this repository: they are found through$QWEN38_EVAL_PATHS, and the prompts, samples, tests, checkpoint and grader are command-line arguments without defaults.Summary of Changes
tools/qwen38_graph/README.mdonnxruntime-genai-cuda;-DENABLE_QWEN38_PLANE=ONadditionally builds a standalone library), the external artifacts a package needs, the package layout, the v12b stack, theSpeculativePrefixCommitcontract (graph I/O and bindings), Engine usage, the scripts, the qualification pass and the limitations.tools/qwen38_graph/qwen38_engine_util.py,smoke.py--text-pool/$QWEN38_TEXT_POOLand--prose-pool/$QWEN38_PROSE_POOL) and a minimal usage example. The pool is repeated when it is shorter than the requested context.tools/qwen38_graph/bench_engine_mtp.py,bench_ttft_engine.pyQWEN38_SKIP_LONG_WARMUP=1skips the warm-up at 32768 tokens and above) and time to first token.tools/qwen38_graph/calibrate_qwen38_kv.pyrotary_dim=64) pair envelope.tools/qwen38_graph/engine_gate.py--referencestream (exact for--prefill steps; prompt length and a minimum prefix agreement for--prefill fast). With--force-rejectevery draft is replaced, so MTP must equal no-MTP: the self-contained gate.tools/qwen38_graph/engine_behaviours.pytools/qwen38_graph/engine_prompt_lengths.pystepsagainstfastprefill.tools/qwen38_graph/mmlu_engine_eval.py,lcb_engine_eval.pylcb-gradercontainer at 16K and 32K caps, paired exact McNemar test) through the Engine API. They import the research helper modules from$QWEN38_EVAL_PATHS.tools/qwen38_graph/run_with_ram_budget.py,test_ram_budget.pytools/qwen38_graph/test_plane_kernels.pyTesting
ruff checkandruff format --checkpass on the files of this PR; every script byte-compiles;python -m unittest test_ram_budget: 2 tests, OK.sm_90) with the Qwen3.8-Flash-Next rc5 INT4 DFlash2 (S=8) package on the merged tip of the runtime series:smoke.pydecodes 75 tokens at 385.9 tok/s (first token 0.050 s, EOS), andengine_behaviours.py --text-pool <the repository's docs, about 500 KB>ends withBEHAVIOURS PASS(27 PASS, 0 FAIL).666/800 (83.25%)at a median361.14tok/s with the DFlash2 S=8 package;engine_behaviours.py27/27PASS.lcb_engine_eval.py(needs the Docker grader and the LiveCodeBench data),test_plane_kernels.py(needs the research environment), the cgroup enforcement ofrun_with_ram_budget.py.Checklist
test_ram_budget.py; the rest are drivers that are run against a package)tools/qwen38_graph/README.md)