Skip to content

feat(server): add in-process multi-model load routing - #715

Closed
Graffioh wants to merge 10 commits into
Luce-Org:mainfrom
Graffioh:codex/heterogeneous-serving
Closed

Graffioh wants to merge 10 commits into
Luce-Org:mainfrom
Graffioh:codex/heterogeneous-serving

Conversation

@Graffioh

@Graffioh Graffioh commented Sep 7, 2026 •

Copy link
Copy Markdown
Collaborator

A single dflash_server can now serve multiple independently batched models behind one endpoint. --next-model starts a separate model option block; requests with model: "auto" select the least-occupied eligible model, while explicit names remain pinned. Two slots per model provide the initial Qwen/R9700 + DS4/Strix 2+2 configuration. Full capacity returns 503 without a global queue.

Each model retains its own tokenizer, chat template, model-card defaults, backend, sequence engine and scheduler. Startup parses every option block once before loading, rejects duplicate names and incompatible options early, identifies the offending block in errors, and prints the listener/model layout. Host/port/CORS are shared. The launch guide includes a copyable command, separate Bash arrays for model settings, and configuration inspection through /props.

Qwen KV overrides now travel through its backend configuration into budgeting and allocation without rewriting environment variables. DS4 uses a fixed cache layout and warns when the previously ineffective KV-type flags are supplied. Its automatic MMVQ width now belongs to its own GPU backend: the old process-wide default of 16 crashed Qwen's batched drafter. A backend crossover setting preserves the original DS4 policy; the existing thread override also forces MoE dispatch, so it cannot express that default faithfully. Explicit environment overrides remain process-wide.

The listener parses JSON and endpoint structure once, then the selected handler applies model-specific defaults and tokenization. Reservations last through engine retirement and output draining, including cancellation. Shutdown waits for workers and all borrowed model contexts to become unused; detached clients publish completion under the same mutex as the shutdown waiter.

Discovery lists the named models and auto in the existing OpenAI and Codex schemas. /props and /status/json expose per-model capacity, occupancy, configuration and worker status. This implementation covers local paged engines and occupancy routing. Context/capability-aware routing, global queueing, conversation affinity and quality collaboration remain outside its scope.

See server/docs/MODEL_ROUTING.md for startup, request selection, setting scopes and validation limits.

Dependencies and review scope

The branch includes #598 at a085cc222c513be0dd9d015fe8f7f8a61b6bcc8c and #707 at 828ecf14a951bcc6ca32dba17da1e958a6e2db8e, merged above main 3ce2b916. The main-based diff includes those prerequisites until they land.

The routing implementation starts at b007d96d. Follow-up commits separate request/lifetime fixes (d3889bf9), model launch configuration (b0afa4e1), and the backend-owned DS4 policy plus validation/docs (2176cbea).

Validation

  • Built for both HIP gfx1151 and gfx1201, verified in all actual HIP compile commands. An earlier validation note incorrectly claimed both targets while CMake had overwritten the generic setting; the final build uses DFLASH27B_HIP_ARCHITECTURES.
  • Model-free server suite: 456 passed, 0 failed. Includes real HTTP/scheduler integration for 2+2 admission, overload, pinning, independent progress, per-model tokenizers/templates/defaults, malformed input, cancellation/reuse, response protocols and shutdown.
  • GPU dispatch regression passes: tested ROCmFP4 projections through 16 columns remain bit-identical to separate single-column computation, and a second backend retains valid Q8 dispatch at 16 columns.
  • Real Qwen3.8-27B IQ4_XS + Q8_0 DFlash2 on R9700 and monolithic DeepSeek-V4-Flash ROCMFP2 on Strix: explicit and automatic C4 routing both reach 2+2, with correct response-model provenance and 503 overload.
  • Both models' generated outputs match between their C2 and mixed C4 runs on two comparison prompts each. DS4 also matches the previous environment-based policy control on both prompts.
  • Repository canonical benchmark: 12/12 requests passed, each returning 128 completion tokens, across three C4 waves of mixed code/prose prompts.
  • Real TCP-reset cancellation and subsequent reuse pass for each model. Shutdown with one active request per model and an incomplete HTTP upload closes every client and exits with status 0; GPUs are released.
  • Seven CLI validation cases pass before model loading. git diff --check passes.

Validation uses 4,096-token configured context limits and short prompts on this exact model/device pair. It does not establish long-context quality, other checkpoints/devices, or a performance improvement. Keep this PR in draft while the prerequisite changes and implementation are reviewed.

Review in cubic

Graffioh and others added 10 commits September 6, 2026 05:58
The DFlash2 concurrent verify graph ran each Gated DeltaNet layer as 31
launches, nine of them glue around two kernels that already fold the same
work on the dense chain: six gate-prep ops over two contiguity copies of
the stacked (beta | alpha) projection, a history gather plus a
non-contiguous concat (45 us per layer at four lanes) feeding the tree
conv, and a 3 MB-per-lane gather of the recurrent base state. The plain
recurrence then wrote per-token intermediates (100 MB per layer at four
lanes) and a final state that nothing reads: the commit replays the log.

Three exact fusions on the mapped tree segment:

- ggml_ssm_conv_tree_step assembles [history slab | x] per mapped slot,
  convolves along the tree parents with silu and writes the window the
  replay-log commit reads; the persistent history stays read-only.
- ggml_gated_delta_net_mapped_verify reads each sequence's base slab
  through the slot map in place and writes neither the final state nor
  the intermediates; the packed result holds the attention output and
  the captured replay log.
- raw gates now apply to that route through strided [1, H, T, S] views
  of the stacked projection, so the contiguity copies go with the ops.

Every kernel keeps the op-by-op arithmetic (same taps and accumulation
order, same sigmoid/softplus expressions), so the served outputs are
byte-identical. test_qwen35_gdn_verify_fusion builds both routes on HIP
and requires bit-identical attention output, replay log, conv output and
conv window, with the persistent states untouched, for the Qwen3.8 shape
and the non-grouped recurrence kernel. DFLASH_QWEN35_NO_FUSED_KERNELS=1
restores the op-by-op graph.

Fixed-C1 on the R9700 (Qwen3.8-27B IQ4_XS, DFlash2 width 8): 109.6 to
118.9 tok/s output-window (+8.4 percent against -0.4 percent bracket
drift), byte-identical.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BHEMrPbVpy2uufaXvgrEKk
Reuse gfx1151 ROCmFP4 weights through sixteen columns, retain narrow F16
MMVF routing, and reduce mixed FP2/FP3 projection overhead while honoring
explicit dispatch ceilings. Use an ordered legacy buffer pool and retain
compatible scheduler staging allocations across graph rebuilds.

Add tail RoPE and exact sink-column softmax on CPU and CUDA/HIP. Handle
large sink-column rows with the existing global-memory fallback, and reject
unsupported modes in other backends. Include kernel regressions and their
build/CI registration.

Validation: targeted HIP build; sink-column regression passes on CPU,
gfx1151 and gfx1201, including shared-memory boundary widths and distinct
row sinks, with zero bit mismatches against scale-concat-softmax. Other
backend capability guards were reviewed but not runtime-tested here.

Co-Authored-By: Codex <codex@openai.invalid>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Share slot lifecycle bookkeeping between Qwen and DeepSeek, and add DS4
paged cache ownership and a sequence engine for monolithic Strix Halo and
R9700 plus Strix serving. Keep per-sequence attention, compressor, sampling,
and cancellation state isolated, with explicit cache memory accounting.

Reuse gathered graph shapes, pack chronological prompt rows, and partition
dense and expert projections at qualified widths. Consolidate gathered
attention data movement, tail RoPE, sink-column softmax, and compressor
flushes while preserving chronological reads and backend ownership.

Include host and model-state regressions, serving documentation, and the
qualified launch recipe. Historical real-model and profiling evidence is
recorded in PR Luce-Org#598; this history cleanup preserves the tested source tree.

Co-Authored-By: Codex <codex@openai.invalid>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Graffioh

Graffioh commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author

Closing this runtime draft as research-only work, as requested. The experiment history, code structure, results, and evidence index now live in draft research PR https://github.com/Luce-Org/luce_box/pull/103 . The implementation branch and local heterogeneous-serving worktree are preserved for future work.

@Graffioh Graffioh closed this Sep 8, 2026
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.

1 participant