perf(daemon): compact retained read tracking state

Merged
JL
5d ago
+911-15

Read tracking retained growable String headers for immutable message IDs and senders across its bounded per-chat collections. Store those values as Box; receipt drains transfer the buffers back into the existing public String types. Limits and behavior stay unchanged, with no new runtime dependencies.

Paired release measurements on the same Linux runner replayed 75,703 synthetic messages over 1,032 chats. Seven instrumented samples saved 3.12 MiB of live heap for unread scenarios (about 18% after publication and 24% after receipt queries). Fifteen uninstrumented samples reduced median peak RSS by 7–11% across headless, attached, group and already-read cases. CPU/wall distributions overlap; these bridge workloads do not measure a complete connected account.

The reproducible harness uses a test-only counting allocator, /proc and wait4, without CodSpeed, eBPF, root or credentials. docs/daemon-memory.md records baseline/candidate commits, commands, distributions and limitations. Synthetic SQLite coverage separately checks account-scale pagination and decoding.

Validation: daemon all-feature library tests (346 passed, 4 profiling workloads ignored in ordinary runs), all-target/all-feature daemon Clippy, formatting and diff checks. All four release profiling workloads were executed repeatedly with correctness assertions.


Summary by cubic

Adds synthetic account-scale coverage and an unprivileged measurement harness for daemon memory, then uses them to compact read-tracker state: IDs and sender strings now use Box<str> instead of retaining unused String capacity. On the recorded replay workloads, live heap after drain drops about 3.1 MiB (~18%) for unread traffic, peak RSS falls by roughly 3.4 MiB, and CPU/wall distributions overlap. Cache limits, receipt semantics, and public types are unchanged.

  • The memory-profiling test feature installs a counting allocator in native test binaries only; production allocators are unchanged.
  • scripts/build-memory-workload.py and scripts/measure-daemon-memory.py run fresh, unprivileged Linux processes with no root, eBPF, or CodSpeed; the driver alternates base/head order, excludes warmups, reports isolated samples, and has failure-path regression tests running in CI.
  • The fixture covers 1,032 chats, 75,703 messages, and 1,653 contacts, asserting pagination without skips or duplicates, stored payload decoding, search limits, duplicate delivery, badges, receipts, and the publication tail with and without an attached subscriber.

Summary by CodeRabbit

  • Performance
    • Chat read tracking now uses less memory in the tested scenarios, with no change to message ordering, timestamps, or read limits.
  • Reliability
    • Large chat histories are tested for complete, duplicate-free paging and valid message data.
  • Documentation
    • Added guidance and comparative results for daemon memory and performance measurements.