Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
826bfc9
spec(LTX25-PHASE-INSTRUMENT): the instrument measures its own cost, a…
mudler Aug 22, 2026
ed60f82
feat(LTX25-PHASE-INSTRUMENT): the phase table charges its own cost an…
mudler Aug 22, 2026
a5d41d1
fix(LTX25-PHASE-INSTRUMENT): the charge is disjoint, the budget is th…
mudler Aug 22, 2026
56cfa01
Merge origin/main into row/LTX25-PHASE-INSTRUMENT-v2
mudler Aug 22, 2026
27f17d1
fix(LTX25-PHASE-INSTRUMENT): the console gate was VACUOUS, the table …
mudler Aug 22, 2026
5faad59
Merge origin/main into row/LTX25-PHASE-INSTRUMENT-v2
mudler Aug 22, 2026
03f0535
spec(LTX25-PHASE-INSTRUMENT): the 45-run distribution taken on the tr…
mudler Aug 22, 2026
d540bee
Merge origin/main into row/LTX25-PHASE-INSTRUMENT-v2
mudler Aug 23, 2026
c7ca014
record(LTX25-PHASE-INSTRUMENT): the suite grew to seven cases and `##…
mudler Aug 23, 2026
6105175
fix(#1755): the sibling emitter kept #1569's defect, and the console …
mudler Aug 23, 2026
b527509
record(LTX25-PHASE-INSTRUMENT): four numbers this row asserted that i…
mudler Aug 23, 2026
e1367db
Merge origin/main b508cbce6 into row/LTX25-PHASE-INSTRUMENT-v2
mudler Aug 23, 2026
61c3f0a
record(LTX25-PHASE-INSTRUMENT): the control mutation and the defectiv…
mudler Aug 23, 2026
825f1e3
test(#1755): the console case set an env var that a thrown preconditi…
mudler Aug 23, 2026
f60b298
record(LTX25-PHASE-INSTRUMENT): the `### 10` gate holds two thirds of…
mudler Aug 23, 2026
223810f
Merge origin/main 66d1b0a90 into row/LTX25-PHASE-INSTRUMENT-v2
mudler Aug 23, 2026
921b03d
record(LTX25-PHASE-INSTRUMENT): the first statement of coverage overs…
mudler Aug 23, 2026
7cb94cf
merge(LTX25-PHASE-INSTRUMENT): bring the branch current with origin/m…
mudler Aug 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .agents/issue-index.md

Large diffs are not rendered by default.

942 changes: 942 additions & 0 deletions .agents/specs/ltx25-phase-instrument.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions .agents/specs/ltx25-phase-residue.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,9 @@ once, at `tests/vllm/multimodal/test_ltx2_video.cpp:4325`, asking for it.
| [#1668](https://github.com/mudler/vllm.cpp/issues/1668) | **the three anchors and the instrument self-cost, as one implementable unit.** `load.dit_config`, `artifacts.mux`, `denoise.update` plus `Ltx2ConditioningTrace::sampler_updates`, and `Record::instrument_seconds` with its conservation invariant. The reference implementation, the gate report and the mutation table stay readable at `refs/pull/1556/head` = `b45ea3bbb` |
| [#1567](https://github.com/mudler/vllm.cpp/issues/1567) | the res_2s arm's `denoise.update` anchor. `Ltx2Res2sDenoisingLoop` runs its own post-process and step behind `Ltx2Res2sHooks`, so the anchor needs a hook rather than a statement. It lives in `ltx2_samplers.cpp`, is declared in `ltx2_samplers.h` beside the hooks struct, and is called from `ltx2_video.cpp`. **NOT `ltx2_res2s.cpp`**: #1556's spec named that file and it has never existed here, which `git log --all --diff-filter=A` confirms; #1567's forge text names no file at all, so the wrong anchor came from the spec rather than from the issue. No gate in this tree renders on that arm, so landing it beside the first-order arm would land dead code |
| [#1568](https://github.com/mudler/vllm.cpp/issues/1568) | the `denoise.step` / `denoise.update` seconds transfer. (1b') compares `start_seconds` only, so leaving `denoise.step` open across the post-process and emitting `denoise.update` empty after it preserves the alternation, both counters, containment, non-overlap, exclusivity, (1c) and (2), while moving 100% of the decomposed seconds onto one name. No (2b) floor separates it: the honest share of `denoise.update` runs 0.45% to 11.15% across four boxes and a transfer puts it at ~0%. Closing it needs an anchor INSIDE the callee |
| [#1569](https://github.com/mudler/vllm.cpp/issues/1569) | a gate on `WriteJson`'s clock ORDERING, **measured green under its own mutation**. Restoring the old order left the conservation case GREEN 10 of 10, at `wall 0.0608987s, unaccounted 0.000534223s, table charge 0.000301655s`, because the copy and sort of a three-record table are nanoseconds. Gating it needs a table with enough records for the sort to be measurable |
| [#1569](https://github.com/mudler/vllm.cpp/issues/1569) | **CLOSED by `LTX25-PHASE-INSTRUMENT`** ([`ltx25-phase-instrument.md`](ltx25-phase-instrument.md)), which gates it over an 8000-record table where the copy and the sort are a measurable event, against a discriminator measured in the same run rather than written down as a constant. On the tree that lands, restoring `main`'s clock order (`M1`) reds it 10 runs of 10 at ratios of 2.080 to 3.418, and the partial regression (`N11`) reds it 10 of 10 at 0.892 to 1.145, against a bound of 0.5 and an honest 45-run maximum of 0.027616 at loadavg 19-26 — 0.018123 in a higher 56-113 regime. The earlier "1.004 against 0.0042" belonged to the WITHDRAWN one-number `copy + sort` budget, which a fresh review broke and `### 6` replaced with `min(copy, sort)`. What it originally owed: a gate on `WriteJson`'s clock ORDERING, **measured green under its own mutation**. Restoring the old order left the conservation case GREEN 10 of 10, at `wall 0.0608987s, unaccounted 0.000534223s, table charge 0.000301655s`, because the copy and sort of a three-record table are nanoseconds. Gating it needs a table with enough records for the sort to be measurable |
| [#1570](https://github.com/mudler/vllm.cpp/issues/1570) | an upper bound on the instrument's own share of a leaf. `uncovered <= 2 * leaf_instrument` is stricter than the floor it replaces only while `leaf_instrument` stays small, and nothing bounds it. Moving the DiT `Tick` out of `Evaluate` would charge ~110 flushed writes to `denoise` and widen the gate while printing a small number |
| [#1571](https://github.com/mudler/vllm.cpp/issues/1571) | a per-gap decomposition IN the emitted table. The 92% region above was found with a scratch script; a reader of `phase-log.json` still cannot see it without one, and the same investigation will be re-derived the next time the residue moves |
| [#1571](https://github.com/mudler/vllm.cpp/issues/1571) | **CLOSED by `LTX25-PHASE-INSTRUMENT`** ([`ltx25-phase-instrument.md`](ltx25-phase-instrument.md)). `phase-log.json` carries `gaps`, and the gate over it is an accounting identity rather than a tolerance: the gaps add to `unaccounted_seconds` by construction. On the fixture render it immediately named the NEXT region, `load.dit` -> `load.video_vae` at 0.627 ms, which is the `load.dit_config` anchor #1668 owes. What it originally owed: a per-gap decomposition IN the emitted table. The 92% region above was found with a scratch script; a reader of `phase-log.json` still cannot see it without one, and the same investigation will be re-derived the next time the residue moves |
| [#1572](https://github.com/mudler/vllm.cpp/issues/1572) | assertion (1c)'s span slack reds intermittently on `main` — `decode.video` at `0.00256913` against a `0.00075` bound, 3.4x. Pre-existing from `6b48edb2c` and not this row's. **STILL OPEN, and two further shapes of that bound are now MEASURED SHUT.** `LTX25-DEVICE-RESIDENCY` built a fifth shape (`4 x` the worst boundary a 1 kHz sampler saw across the whole case) and a sixth (`4 x` the worst inside the record's OWN window) and withdrew both: the fifth lets one 200 ms descheduling of the sampler thread turn a real 20 ms un-named phase from red 9 of 9 into a GREEN case, and the sixth reds an unmutated tree 10 times in 45 consecutive runs at loadavg 21.8-61.5 -- of which **5 in 45 is the defensible figure**, because a second mechanism was identified and repaired while that population was still running, so its reds were measured on a binary that predates its own repair. See `.agents/specs/ltx25-device-residency.md` `### The span-slack bound, FIFTH and SIXTH shapes` for both distributions and for the one hypothesis that has not been tried |
| [#1619](https://github.com/mudler/vllm.cpp/issues/1619) | **the `merge=union` driver duplicates a row, MEASURED on this row's own merges.** Both sides appended before the same trailing anchor rather than at the true end, so the driver concatenated two regions that each carried `#1546` and the resolved index held it TWICE, byte-identical, at 538 lines where the correct union is 537. `git merge-tree` called that merge clean and `check-issue-index-append-only.py` passed it, because a duplicate is an ADDITION and that checker only collects removals. `check-agent-record.py` did NOT pass it -- a claim #1556's spec made and this row REFUTED by reproduction: regenerating the raw driver output and running that same tree's checker returns rc=1 with `issue #1546 listed twice`, and the refusal has existed since `8dd6508da` (2026-08-09), before the merge. So the blind gate is exactly one checker, not two, and the gap is narrower than #1556 recorded. The de-duplication half is CONDITIONAL, and the condition is what #1556's spec omitted: the checker reds a repair only when the DUPLICATE IS ALREADY IN THE BASE. Measured at three pairings -- `--base e2a9e035d` against the real canonical 537-line file rc=0, against a synthetic 537 rc=0, and `--base <committed 538> --head <537 de-dup>` rc=1. It diffs `merge-base..HEAD`, so when the base predates the duplicate the addition and the removal CANCEL and it passes. Since `origin/main` is preflight's base, and is the shape this branch used, the gate does NOT red someone who repairs driver output before committing it -- only someone repairing a corruption that already landed. The same range property is why relocating a base-reachable row DOES red it: moving row `#168` to the end gives rc=1 and a `removed:` line naming it. So "de-duplicating in place FAILS the checker", as #1556's spec put it, is false unqualified and true once the duplicate is base-reachable. #1556's spec added that the same driver dropped `#838` on a later re-merge, making this a recurring class; that is WITHDRAWN as unreproducible. Re-running `git merge-file --union` at every later merge where `#838` was on a side leaves it present in all of them, and `git log -S` finds it absent from no committed state -- mechanically a union driver cannot drop a line that is an addition on one side. If it ever went missing, that points at a wholesale take-ours resolution rather than at the driver |
| [#1439](https://github.com/mudler/vllm.cpp/issues/1439) | **NOT closed by this row, and it must not be.** See `## Risks and decisions` D4 |
Expand Down
12 changes: 12 additions & 0 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,18 @@ thread count they actually got beside the count that was asked for.
than `max_model_len` tokens and would be refused after tokenizing anyway.
Send a shorter prompt, or load a checkpoint with a longer context.

- A video render writes `<output_dir>/phase-log.json` beside its frames, and
`unaccounted_seconds` there is time the render spent inside no named phase.
Read `gaps` to find out WHERE: it holds one interval before each named phase
and one after the last, each naming the two phases it lies between, and they
add to `unaccounted_seconds` exactly. The largest entry is the region worth
naming next. Subtract `instrument_seconds` first — that is what the
instrument itself spent on its own phase boundaries, and on a short render it
can be about half the residue. Every phase record carries its own
`instrument_seconds` too, which is what that phase paid for the boundaries of
its sub-phases. The C ABI hands back the same file's path through
`vllm_video_last_phase_log`.

## Find a focused guide

[Task guides](guides/README.md) cover workflows that apply to more than one
Expand Down
12 changes: 12 additions & 0 deletions docs/models/ltx-2-5.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,18 @@ Use `sum_leaf_seconds` for the accounted total. `unaccounted_seconds` reports
time outside named phases. The file labels itself as diagnostic output, not a
benchmark.

`gaps` says WHERE that un-named time is. It holds one interval before each named
leaf and one after the last, each carrying the two names it lies between, and
they add to `unaccounted_seconds` exactly. Sort it and read the top entry: the
largest gap is the next region worth naming. `<origin>` and `<end>` are the ends
of the timeline.

`instrument_seconds` says how much of the residue the instrument itself spent —
the mutex wait before a phase starts, and the flushed progress line after it
ends. Subtract it before calling what is left a phase nobody named. Every record
carries its own `instrument_seconds` too, which is what that phase paid for the
boundaries of its own sub-scopes.

Set `VLLM_RENDER_PHASE_LOG_STDERR=1` to print the phase table. Set
`VLLM_RENDER_PHASE_SAMPLER=0` to disable the 100 ms memory sampler. The normal
`[render]` lines print phase boundaries and DiT-forward progress.
Expand Down
34 changes: 34 additions & 0 deletions include/vllm/multimodal/render_phase_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ struct Record {
int64_t peak_device_bytes = -1; // -1 => no device probe was installed on this arm
bool span = false; // printed for context, never summed
bool nested = false; // opened while another leaf was open; excluded from the sum
// HOW MUCH OF THIS RECORD'S OWN DURATION THE INSTRUMENT SPENT, outside every
// child of it. Row LTX25-PHASE-INSTRUMENT, issue #1668. See the note on
// `PhaseLog::Instrument` below: this is the number that separates "a phase
// nobody named" from "the cost of naming the phases", and until it existed
// nothing could tell the two apart.
double instrument_seconds = 0.0;
};

// Resident set size in bytes, or -1 where the platform publishes none.
Expand Down Expand Up @@ -120,6 +126,34 @@ class PhaseLog {
std::vector<Record> Records() const;
int64_t Samples() const;

// ── WHAT THE INSTRUMENT ITSELF COST (row LTX25-PHASE-INSTRUMENT, #1668) ───
//
// The wall this instrument spent inside its own entry points while NO leaf
// was live — the process-wide mutex wait before `Open` stamps a start, the
// flushed progress line and the vector erase after `Close` stamps an end. It
// is therefore the part of `unaccounted_seconds` this instrument produced
// rather than the render.
//
// WHY IT IS PUBLIC AND NOT A DETAIL. Until it existed, a reader of the table
// — and every gate over it — could only compare the residue against a SHARE
// of the render's wall, and a share is a property of the fixture rather than
// of the code: [#1439](https://github.com/mudler/vllm.cpp/issues/1439)
// measured the same 95% floor deciding by box load at 64x64x9, while the same
// residue would be invisible on the 21 B render this instrument exists for.
// The per-record half is `Record::instrument_seconds`, and the two partition
// every interval this instrument spends: whatever a live leaf does not
// absorb is charged here.
//
// IT IS NOT A BUDGET, AND THAT IS A DECISION WITH EVIDENCE BEHIND IT. The
// obvious use — `residue <= 2 * instrument`, a scale-free replacement for the
// two wall-clock ratios — was measured over hundreds of runs and WITHDRAWN:
// the un-instrumented remainder of a boundary dilates FASTER than the
// instrumented part under contention, so that comparison has a heavy right
// tail (4 red in 45 runs at load 88, max 4.115). It is recorded in
// `.agents/specs/ltx25-phase-residue.md` `## Design` 3. Read that before
// putting this quantity in a denominator.
double Instrument() const;

// Write the table as JSON. Returns false with *why set on an IO failure — a
// render must not fail because its instrument could not write.
bool WriteJson(const std::string& path, const std::string& family,
Expand Down
Loading
Loading