Skip to content
9 changes: 6 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,12 @@ not selected.

Cua-S1 and Open-Jev compute their decision heads on the CPU after downloading
the final hidden state. Cua-S1 screenshots can opt into request-local
aligned token/position prefix reuse with fixed-M64 or full-prompt-matched GEMMs,
host features and language Graph off. Captured contents belong to one request; one engine-owned storage
allocation may retain capacity for later captures. Suffixes execute independently,
aligned token/position prefix reuse with fixed-M64 or full-prompt-matched GEMMs.
Fixed-M64 prefix modes use host features and language Graph off; matched prefixes
support borrowed resident feature windows and bounded language Graph replay.
Current rows are staged outside capture; entries own both recorded prefix
allocations until synchronized retirement. Captured contents belong to one
request; one engine-owned storage allocation may retain capacity for later captures. Suffixes execute independently,
and the existing letter head and token accounting are preserved. Decider projects
its selected LM-head rows on CUDA.
JEMM uses the shared Qwen executor with separate unmerged
Expand Down
101 changes: 94 additions & 7 deletions recipe/cua_s1/native_screenshot.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ multimodal adapter and reports prompt-token usage with zero generated tokens.

## Execution controls and limits

`CUA_S1_GRAPH=1` enables host-feature language Graph replay;
`CUA_S1_GRAPH=1` enables language Graph replay for host or resident features;
`CUA_S1_VISION_GRAPH=1` independently enables vision Graph replay.
`CUA_S1_DEVICE_FEATURES=1` keeps vision features on the GPU and copies image rows
directly into language scratch. Its language path remains eager; it can be paired
with either vision Graph setting. All three controls default off. See the
directly into language scratch before capture/replay. It can be paired with
either vision Graph setting. All three controls default off. See the
[resident-feature contract](native_vision_graph.md#gpu-resident-vision-features)
for strict control parsing, synchronization and reproduction commands.

Expand Down Expand Up @@ -121,8 +121,9 @@ or less than 64 shared tokens, uses complete fixed passes and never reads a
previous snapshot. Retained capacity is additional device memory, separate from
the vision-cache budget.

All active prefix modes require host features and language Graph off; vision Graph
remains independently selectable. They keep the existing prompt, CPU letter head,
The `fixed` and `shared` modes require host features and language Graph off.
`matched` supports host or resident features and either language Graph setting;
vision Graph remains independently selectable. They keep the existing prompt, CPU letter head,
answer order and usage accounting. Fixed GEMMs can round differently from default
execution: compare `shared` with `fixed` for continuation parity, and separately
report probability drift/decision changes against `off`. No automatic mode or
Expand Down Expand Up @@ -185,8 +186,10 @@ and restore the ordinary/fixed-M64 handle selection before returning/unwinding.
Descriptor equality and algorithm support do not establish arithmetic invariance
across row counts on every GPU. Qualify the exact GPU/cuBLAS/model combination
before relying on ordinary-output parity. Keep `off` as the ordinary numerical
control and `fixed`/`shared` as the separate M64 controls. No automatic policy,
language Graph integration, changed prompt or new precision profile is enabled.
control and `fixed`/`shared` as the separate M64 controls. No automatic policy, changed prompt or new precision profile is enabled.
With `CUA_S1_GRAPH=1`, admitted matched prefixes and suffixes use bounded window
Graphs; with `CUA_S1_DEVICE_FEATURES=1`, current image rows are copied directly
from the borrowed vision output into owned language scratch.

```sh
cargo test --release --locked -p omni-qwen3-5-native --test kernels \
Expand Down Expand Up @@ -239,3 +242,87 @@ and acquisition scripts, failures and final-source mapping are in the
[2026-10-26 qualification](https://github.com/Levius-Fubuki/system1-omni/releases/download/cua-mm-qualification-20261026/cua-mm-matched-qualification-20261026.tar.gz). Original real screenshot pixels are omitted.
These measurements precede the startup-symbol guard. That guard has host-only
missing-symbol regression coverage; no new GPU numerical or timing run is claimed.

### Resident matched prefixes with window Graphs

```sh
export CUA_S1_MM_PREFIX=matched CUA_S1_DEVICE_FEATURES=1
export CUA_S1_GRAPH=1 CUA_S1_VISION_GRAPH=1
# Keep prefix=off as the ordinary complete-request numerical control.
```

The matched implementation is shared with PR184; this extension combines it
with the resident language-Graph path. Prefix reuse removes repeated computation
across questions; any combined speedup must be attributed to that work as well
as Graph submission savings. A single question or incompatible GEMM plans still
uses ordinary independent execution, preserving the selected Graph/device mode.

Host and device windows use the same token/T-H-W prefix planner and CPU letter
head. Checked device row slices retain the vision producer borrow. The consumer
copies current rows into its own scratch before capture; no vision pointer is
recorded. Device window exits drain the language stream, including errors.

Window Graph keys contain absolute begin/end rows, both source and destination
prefix allocation identities, and the selected GEMM handle. Entries retain both
prefix allocations, including the simultaneous continue-and-capture case. This
makes producer release and prefix-storage replacement safe. At most 128 window
Graphs are retained; eviction drains first. Scratch growth and matched-workspace
retirement clear affected captures after synchronization. Recording failure keeps
the warmed eager result, disables all language Graph modes and retires their
caches. Vision Graph is independent. Retained snapshot allocations, Graph objects
and up to 16 matched 32 MiB workspaces add GPU memory beyond the vision budget.

Warm the largest request and the complete shape working set, then check traces
for new captures or failures in the measured region. Cold capture and cache
churn must be reported separately; all switches remain opt-in.

```sh
CUA_S1_GRAPH=1 CUA_S1_DEVICE_FEATURES=1 CUA_S1_MM_PREFIX=matched \
cargo test --release --locked -p omni-cua-s1-native --lib prefix_tests \
-- --ignored --test-threads=1 --nocapture
# Repeat with vision Graph0 and1.
CUA_S1_TEST_MODEL="$CUA_S1_MODEL" cargo test --release --locked \
-p omni-qwen3-5-native --lib model::graph_tests \
-- --ignored --test-threads=1 --nocapture
```

### Recorded resident matched qualification

On RTX 4090 / SM8.9 / CUDA 13.0, the 2026-10-26 frozen complete-request
comparison measured the following. O is original PR183 at `911faa0d`, E is
resident matched prefix eager, and G is resident matched prefix with window
Graphs. All use vision Graph and the same pinned artifacts. Each mode has 64
synthetic requests and 96 requests from 12 fixed real screenshots, concurrency 1.

| Workload / mode | Mean ms | p50 ms | p95 ms | Sampled process maximum MiB |
|---|---:|---:|---:|---:|
| Synthetic / O | 130.257 | 117.968 | 269.950 | 10202 |
| Synthetic / E | 105.979 | 102.867 | 169.251 | 10448 |
| Synthetic / G | 104.902 | 101.780 | 172.540 | 10538 |
| Real / O | 248.819 | 258.092 | 263.407 | 10256 |
| Real / E | 150.949 | 151.120 | 157.391 | 10606 |
| Real / G | 147.868 | 148.416 | 154.275 | 10694 |

G reduces the real mean by 40.6% and p95 by 41.4% versus O, with 438 MiB higher
sampled process maximum. Relative to E, Graph reduces the real mean by 2.0%; the
large combined gain therefore includes prefix computation reuse. Synthetic mean
falls 19.5% versus O, while the smallest two-question case regresses 4.8%; G's
synthetic p95 is 1.9% higher than E. These are scoped measurements, not a default-on
recommendation or a universal speedup.

Two balanced O/E/G/G/E/O visits per suite each exclude a growth traversal, a
stabilization traversal and five warmups, then time four shuffled traversals.
The 480 timed HTTP samples include response parsing/schema validation; 300
excluded and 135 feasibility samples remain separate. No timed new capture or
capture failure occurred. Five profiles each produced 192 regular numerical
records: raw logits, full responses and token/T-H-W inputs match original O
exactly, including separate single-question extraction and malformed-input
recovery. Cold/growth timings and startup are retained separately. Real quality
remains 119/192 correlated choice permutations, with existing native-vs-FP32
reference limitations; this is not official ScreenSpot accuracy.

The [raw qualification and portable audit](https://github.com/Levius-Fubuki/system1-omni/releases/tag/cua183-resident-20261026)
bind source/build/model pins, corpus reconstruction, cold and measured samples,
per-case regressions, memory, admission traces and GPU lifecycle tests. Original
screenshot pixels are omitted. Other hardware, concurrent serving and general
GUI task quality require separate qualification.
53 changes: 49 additions & 4 deletions recipe/cua_s1/native_vision_graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,37 @@ For optional cache and capture/replay messages, set `CUA_S1_GRAPH_TRACE=1`. Fail
are unconditional. Requests execute serially through the existing worker runtime;
this feature does not add batching or concurrent forwards.

## Warming the complete working set

Language scratch growth invalidates earlier language Graphs. Exercise the largest
input first, then warm every measured sequence length and vision grid. Five
warmups alone need not cover a heterogeneous workload. With tracing enabled,
check for timed replays and no new captures or fallback before describing a run
as stable replay. If the real workload exceeds the cache, include and report
its capture/eviction costs instead.

Entry and byte limits must both fit the intended working set. The recorded
8-payload synthetic matrix uses six grids: its 1024-square image alone requests
262537216 bytes, leaving too little of a 256 MiB budget for the smallest grid.
The original timed rounds therefore contained 15 vision captures (3/6/6), plus
5 language captures after scratch growth in the first round. The original
aggregate latency comparison is not a pure warmed-replay measurement.

For that bounded matrix, explicitly setting `CUA_S1_VISION_CACHE_ENTRIES=8` and
`CUA_S1_VISION_CACHE_BYTES=1073741824` eliminated timed vision captures after full
warming; these are workload-specific settings, not new defaults or a total GPU
memory limit. On RTX 4090 / SM8.9, matched resident eager/Graph p50 was
116.891/116.399 ms and p95 was 271.109/269.011 ms (24 timed requests per mode,
3 rounds, concurrency 1). Sampled process maxima were 10138/10202 MiB. This small
sample does not establish a general acceleration: Graphs reduce submission
work, while GEMMs, input staging/checks, CPU preprocessing/readout and stream
synchronization remain. Defaults stay off.

The [follow-up qualification](https://github.com/Levius-Fubuki/system1-omni/releases/download/cua-mm-qualification-20261025/cua-mm-followup-qualification-20261025.tar.gz)
preserves both cache settings, raw/excluded samples, capture traces, source pins
and the full-warming protocol. This follow-up uses the unchanged runtime from
`a14e1027e7de7507e6ff82b3844a916ff19a26b9`.

## Build and launch

Use the pinned base and multimodal adapter revisions listed in the
Expand Down Expand Up @@ -104,8 +135,12 @@ export CUA_S1_DEVICE_FEATURES=1
```

This switch is independent of `CUA_S1_VISION_GRAPH`. Vision can run eagerly or
replay a Graph; the resident-feature language path remains eager in both modes.
The host-feature language path retains the independent `CUA_S1_GRAPH` control.
replay a Graph; `CUA_S1_GRAPH=1` independently enables language capture/replay
for both host and resident features. Current token IDs, T/H/W positions and
image rows are staged before capture/replay into language-owned scratch. Captures
do not retain the borrowed vision allocation; host/device calls with the same
sequence length share the existing multimodal cache. Scratch growth and capture
failure retain the existing invalidation and eager-fallback behavior.
The resident path reuses one vision output across all questions in the request
and copies contiguous image-placeholder rows directly into language scratch.
It avoids the full feature download and per-question feature upload. It still
Expand Down Expand Up @@ -142,14 +177,24 @@ The finite-scan test needs only `CUA_S1_CUDA_LIB`; the other tests need all four
```sh
cargo test --release --locked -p omni-qwen3-5-native --lib device_tests \
-- --ignored --test-threads=1
CUA_S1_VISION_GRAPH=0 cargo test --release --locked -p omni-cua-s1-native \
CUA_S1_GRAPH=1 CUA_S1_VISION_GRAPH=0 cargo test --release --locked -p omni-cua-s1-native \
--lib device_feature_tests -- --ignored --test-threads=1
CUA_S1_VISION_GRAPH=1 cargo test --release --locked -p omni-cua-s1-native \
CUA_S1_GRAPH=1 CUA_S1_VISION_GRAPH=1 cargo test --release --locked -p omni-cua-s1-native \
--lib device_feature_tests -- --ignored --test-threads=1
cargo test --release --locked -p omni-qwen3-5-native --lib device_vision_graph_ \
-- --ignored --test-threads=1
```

The language-Graph regression also runs with the real library:

```sh
CUA_S1_TEST_MODEL="$CUA_S1_MODEL" cargo test --release --locked \
-p omni-qwen3-5-native --lib device_multimodal_graph_ \
-- --ignored --test-threads=1 --nocapture
```

It checks changed tokens/features/positions, host/device interleaving after
producer release, scratch growth, and actual recording-error eager fallback.
These tests compare feature bits, hidden states, logits, probabilities and
complete responses across changed pixels/goals, repeated questions, different
grids with equal patch counts, scratch growth and short-request recovery.
Expand Down
8 changes: 5 additions & 3 deletions src/models/cua_s1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,11 @@ prompts with the same fixed GEMMs; unset/`off` preserves default execution.
The `matched` opt-in instead checks the ordinary full-prompt GEMM algorithms
for all questions and supports each prefix/suffix shape before sharing. If plans
differ or a window is unsupported, it runs ordinary independent full prompts;
a single question also uses the ordinary path. All active prefix modes reject
language Graph and resident features at startup. Prefix contents
are request-local and branches execute serially. One engine-owned snapshot storage
a single question also uses the ordinary path. `fixed` and `shared` reject
language Graph and resident features at startup. `matched` supports both, using
checked device row windows and bounded Graph capture/replay. Graph entries retain
any recorded source/destination prefix allocations and retire after stream drain.
Prefix contents are request-local and branches execute serially. One engine-owned snapshot storage
slot grows as needed; each shared request recaptures it before use. Requests with
no shared prefix ignore the retained contents. Prompt construction, the CPU
letter head, answer order and token accounting are unchanged. Fixed versus default
Expand Down
76 changes: 55 additions & 21 deletions src/models/cua_s1/native/src/vision_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,28 +217,62 @@ impl VisionEngine {
);
if self.prefix_mode == prefix::Mode::Matched {
let (lengths, windows) = prefix::matched_windows(&prepared.prompts)?;
let features = self.vision.forward(&prepared.image)?;
let result = self
.language
.with_matched_prefix(&lengths, &windows, |model| {
prefix::execute(
model,
&self.letters,
prepared,
&features,
prefix::Mode::Shared,
&mut self.prefix_storage,
)
})?;
if let Some(logits) = result {
Ok(logits)
if self.device_features {
let features = self.vision.forward_device(&prepared.image)?;
let result =
self.language
.with_matched_prefix(&lengths, &windows, |model| {
prefix::execute_device(
model,
&self.letters,
prepared,
features,
&mut self.prefix_storage,
)
})?;
if let Some(logits) = result {
Ok(logits)
} else {
prepared
.prompts
.iter()
.zip(counts)
.map(|(p, n)| {
Self::raw_score_device(
&mut self.language,
&self.letters,
p,
&features,
n,
)
.map(|(_, logits)| logits)
})
.collect()
}
} else {
prepared
.prompts
.iter()
.zip(counts)
.map(|(p, n)| self.raw_score(p, &features, n).map(|(_, logits)| logits))
.collect()
let features = self.vision.forward(&prepared.image)?;
let result =
self.language
.with_matched_prefix(&lengths, &windows, |model| {
prefix::execute(
model,
&self.letters,
prepared,
&features,
prefix::Mode::Shared,
&mut self.prefix_storage,
)
})?;
if let Some(logits) = result {
Ok(logits)
} else {
prepared
.prompts
.iter()
.zip(counts)
.map(|(p, n)| self.raw_score(p, &features, n).map(|(_, logits)| logits))
.collect()
}
}
} else if self.prefix_mode != prefix::Mode::Off {
let features = self.vision.forward(&prepared.image)?;
Expand Down
Loading
Loading