Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
360 changes: 360 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 a 4000-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. Restoring the old order now reds it at a ratio of 1.004 against a 50-run honest maximum of 0.0042 under load 103-131. 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 |
| [#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/models/ltx-2-5.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,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