Repository navigation
[Performance] 极限设备性能宪章与长期预算 #12
Description
Objective
Keep TUT responsive and resource-bounded on old, low-power, low-memory systems. This is a long-lived performance contract, not a one-time benchmark exercise and not a reason to trade away correctness, portability, privacy, or maintainability.
Direction and evidence remain outside repository documentation: production invariants, deterministic tests, typed bounded logs, CI, release artifacts, and this issue carry the contract.
Enforced baseline
- Source input is capped at 32 MiB; path reads remain positional and stdin is copied into an immutable private snapshot.
- Terminal geometry, ratatui double buffers, visible render storage, line/search checkpoints, highlight targets, match blocks, row neighborhoods, and queries all have explicit hard limits.
- Line indexing, search, viewport location, and visible rendering advance incrementally; projected-row work yields at grapheme emission boundaries.
- Repeated line lookup, navigation, highlighting, rendering, and source-window work have deterministic counters that prevent replay and allocation regressions.
- Default execution remains quiet: no telemetry, network access, worker threads, idle work, or timing overhead.
- Optional typed logs contain aggregate counters and durations only; they never contain paths, names, text, queries, keys, or terminal contents.
Target environment
ThinkPad X230-class dual-core CPU, 2 GiB available memory, ordinary SSD, and 80x24 terminal. Inputs are 1, 8, and 32 MiB UTF-8 text with ASCII, CJK, emoji, long-line, no-newline, dense-match, and pathological-grapheme cases.
Long-term budgets
| Metric | Target | Regression line |
|---|---|---|
| 1 MiB open-to-first-frame | <= 30 ms | > 100 ms |
| 32 MiB open-to-first-frame | <= 500 ms | > 1 s |
| Peak RSS | <= input x 1.5 + 16 MiB | > input x 2 + 32 MiB |
| Scroll/page p99 | <= 16.7 ms | > 33 ms |
| First search result at 32 MiB | <= 100 ms | > 300 ms |
| Idle CPU | approximately 0% | > 0.5% |
| Release binary | <= 1 MiB | > 2 MiB |
Wall-clock values are hardware observations, not portable correctness assertions. CI should fail on deterministic byte, window, allocation, capacity, step, and output bounds; timing results require recorded environment and repeated samples.
Measurement contract
- Record commit, toolchain, OS, hardware, terminal geometry, workload, sample count, and p50/p95/p99.
- Use at least five warm samples; report cold/cache-miss results separately when relevant.
- Separate ingest, UTF-8/grapheme segmentation, line indexing, layout, rendering, terminal draw, navigation, and search.
- Measure delivered bytes, source windows, segmentation progress, allocation attempts/capacities, background steps, frame work, binary size, and peak RSS before drawing timing conclusions.
- Exercise end-to-end latency through a real PTY as well as pure algorithm fixtures.
- Reject performance claims based only on the best run, OS page cache, or a microbenchmark that bypasses the TUI boundary.
Acceptance
- Provide a reproducible code/test command for the fixed workload matrix without production credentials or network access.
- Emit a machine-readable bounded result suitable for comparison without adding free-form production logging.
- Gate deterministic resource and replay bounds in CI; publish timing/RSS baselines as issue or release records, not repository docs.
- Demonstrate stable degradation or typed refusal at the 32 MiB and terminal/render limits without swap storms or aborts.
- Prove resize storms, continuous navigation, repeated searches, suspend/resume, and error retries do not cause cumulative cache growth.
- Track unexplained regression-line breaches with a focused issue and recovery plan before release.
Scope
Each change must close a measured or provable gap in an independently reviewable slice. This charter does not authorize feature expansion, speculative abstraction, wall-clock-only CI, repository documentation, benchmark theater, or broad rewrites without evidence.
Activity
m1ngsama commentedon Aug 10, 2026
Post-v0.0.4 design note: the next independently reviewable performance slice can satisfy the first three acceptance items without adding production telemetry or wall-clock CI.
Proposed command and output contract
make bounded-results | tee target/tut-bounds-v1.ndjsonThe command would run only
cfg(test)instrumentation and emit a fixedtut-bounds/v1NDJSON stream:u64counters;CI should assert algorithmic ceilings and schema/output bounds, while retaining measured totals for comparison. It should not freeze today's exact totals as a golden file that prevents later optimizations.
Fixed workload set
All core cases use an
80x24terminal and execute load → first complete frame →G→ fixed search to completion →n→ stable frame.x\0.x\0, one long no-newline line, and 32 exact 1 MiB EGCs.Inputs should be generated into one temporary file in fixed 64 KiB chunks and removed between cases, so the harness never retains the whole matrix in memory. Separate records should prove atomic refusal at source+1, terminal geometry, and visible-render limits; FakeDriver/TraceRecorder should prove one bounded operation per loop; the existing PTY fixture should prove cleanup/termios/typed-log shape without recording elapsed time.
Deterministic gates
The runner should retain the existing hard contracts rather than introduce timing thresholds:
The repository already has the required
DocumentMetrics, render/search reserve counters,RuntimeRecorder, FakeDriver/TraceRecorder, and real PTY fixtures. The implementation should therefore be limited to a test-only workload generator/aggregator, a fixed no-dependency NDJSON formatter, minimalcfg(test)getters, a Make target, and one stable-Ubuntu CI invocation. Rust 1.88 and macOS should continue compiling this code through the existing gates without redundantly running the large matrix.This is a design record only; no production API, dependency, repository documentation, credentials, network step, or timing gate has been added yet.
m1ngsama commentedon Aug 11, 2026
PR #105 merged as
191bdec510fc70010a16e43ca0dc98ddc1fecc3band completes the first three acceptance items.Evidence:
make bounded-resultsemits exactly 16 ASCII NDJSON records (8,418 bytes total; largest record 626 bytes) for the fixed 1/8/32 MiB matrix.The issue intentionally remains open. A separately reviewable follow-up will close the remaining storm/retry capacity proof and record the existing regression-recovery evidence before final closure.
m1ngsama commentedon Aug 11, 2026
Correction to the preceding status note: PR #105 fully completes acceptance items 1 and 2 and installs the deterministic CI gate portion of item 3. Item 3 remains unchecked until a real, environment-recorded timing/RSS baseline (including at least five warm samples and separate cold observations) is published here or in release records. No timing/RSS values are inferred from CI counters.
m1ngsama commentedon Aug 11, 2026
Final external PTY baseline — audited
Final evidence was recorded from clean
main == origin/mainat commit355ce364cf8ecce80be69192c68fe075a7d0f994.Evidence identity:
cdcadd3645002ea7c477584fdf466a8dd6a0a5c98284449ad129ddd1ee0a8ce5ffe6ab4e05f7f3e04c4068abdd02d04272c49e531428debb9e148b18219b645a1860fb04f630fc0e6817c718409d959c28b4b1e4f9c0b1a2015ff8b671036077033b5f18af3117b17f9d1b5b2a65da01be80dc7e9254fd7f794a659959919a2bbd92cbb8b6a5e720718d9d87b3a68001145d2720168ffe43d0a33f5076a1948bcabe76120222f040ba19de1c0501e10518f638166b412614e94ffdf47cd0eb2dEnvironment: Apple M4, 10 cores, 24 GiB memory, arm64, macOS 15.7.3 build 24G419, Rust 1.97.1, LLVM 22.1.6, fixed 80×24 PTY,
TERM=xterm-256color,LC_ALL=C.Sampling used nearest-rank percentiles:
Latency aggregates
Values are p50/p95/p99 in milliseconds.
Resource aggregates
RSS values are p50/p95/p99/maximum in MiB. Idle CPU values are p50/p95/p99 percentages.
The idle CPU clock has 10 ms resolution. A zero result therefore means below a 0.033333% upper bound over the 30-second window, not mathematically zero CPU use.
Budget evaluation
The conservative value uses the worst class p99 for latency, maximum observed RSS, and worst idle p99.
All 220 samples exited successfully with empty stderr, restored termios, valid terminal lifecycle ordering, exactly one alternate-screen enter/leave, required cursor cleanup, and zero swap operations.
The macOS
wait4and/usr/bin/time -lRSS channels both reported 2,981,888 bytes for the cross-check scenario; the latter also reported a 2,261,280-byte peak memory footprint and zero swaps.Limits of this evidence
open(2)duration.No measurement gate failed and no regression-line breach was observed. This run therefore does not trigger a focused recovery issue.
m1ngsama commentedon Aug 11, 2026
Deterministic resilience and governance closure
PR #107 merged as
355ce364cf8ecce80be69192c68fe075a7d0f994; its pull-request CI and post-merge main CI both passed on current Ubuntu, Rust 1.88 Ubuntu, and current macOS.The test-only capacity proof now accounts component-by-component for line checkpoints, both document windows, row-neighborhood edges, both active locator queues, stale or scanning render storage, the full search session, and active/help-return search drafts. It samples after every action, background phase, and draw. One maximum warm round is followed by eight verification rounds whose every component must remain at or below its warm high-water mark.
The fixed resilience matrix covers:
Each sequence also checks its functional end state. Transition tests separately force nonzero scanning render storage, stale cached render storage, both locator queues, and help-return draft storage so the accounting cannot pass through unreachable fields.
Acceptance item 4 is supported by the deterministic source, terminal-geometry, visible-render, and frame-symbol boundary/refusal tests from #105 and #104, plus the final 220-session PTY baseline above: all limit failures are typed and atomic, retries succeed, and observed swap operations and aborts were zero. Acceptance item 5 is covered by #107. No production telemetry, timing gate, background work, or public API was added.
Regression-governance audit
The historical record is mixed and is recorded without retroactive polishing:
2026-08-10T16:23:24Zwith the approximately 157 ms pathological-frame observation and a recovery plan. v0.0.3 shipped only 26m11s later and did not disclose it.18:13:49Z, before v0.0.4.2026-08-10T23:04:29Z; the fixture demonstrated a 115,277,824-byte combined request and at least a 48,168,960-byte under-count relative to the named 64 MiB budget. v0.0.5 shipped 8h15m later and explicitly disclosed #87.2026-08-11T07:55:08Z, 35m33s after that release and before any later release.Prospective rule recorded by this closure:
At this snapshot, there is no recorded untracked or unexplained budget breach. That is a governance statement, not proof that every future workload on every machine meets every wall-clock target. The audited external baseline found no new regression-line breach, so no additional recovery issue is required before closing this charter.