feat(memtrack): collect RSS via rss_stat and folio-rmap reconstruction#453
feat(memtrack): collect RSS via rss_stat and folio-rmap reconstruction#453not-matthias wants to merge 12 commits into
Conversation
Merging this PR will not alter performance
|
Greptile SummaryThis PR adds RSS tracking to memtrack. The main changes are:
Confidence Score: 4/5This is close, but one startup failure should be fixed before merging.
crates/memtrack/src/ebpf/memtrack.rs Important Files Changed
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
crates/memtrack/src/ebpf/memtrack.rs:588-590
**Lifecycle attaches still abort**
The `rss_stat` attach now warns and continues, but these new RSS lifecycle tracepoints still use `?`. If a host can run the existing allocator probes but lacks or disables `task:task_newtask`, `sched:sched_process_exec`, or `sched:sched_process_exit`, `attach_tracepoints()` returns an error before the tracker starts. That keeps memory tracking unavailable on a host where only the RSS accounting side is unsupported. Make these lifecycle-only attaches best-effort as well, or gate RSS reconciliation on the lifecycle tracepoints that attach successfully.
Reviews (5): Last reviewed commit: "test(memtrack): validate fork-seeded chi..." | Re-trigger Greptile |
d992a0a to
b670b0a
Compare
Sample the kernel's per-mm resident counter through the kmem:rss_stat tracepoint, emitting absolute byte values per mm member. Adds the EVENT_TYPE_RSS contract, MemtrackEventKind::Rss, the parser arm, a writer bench case, and a gated integration test.
Attach fentry hooks on the anon folio-rmap add/remove functions, emitting signed page-count deltas so anon RSS can be reconstructed over time. Gated behind CODSPEED_MEMTRACK_TRACK_RMAP; the programs stay autoload-off by default so the skeleton loads on any kernel. Adds the EVENT_TYPE_RMAP_ANON contract, MemtrackEventKind::RmapAnon, parser arm, and bench case.
Add a gated integration test that ramps anon RSS via mmap/munmap, reconstructs it from RmapAnon page-count deltas, and asserts the estimate tracks the rss_stat MM_ANONPAGES peak within 25%.
b670b0a to
2f41984
Compare
test(memtrack): snapshot per-process RSS and rmap reconstruction against /proc
A forked child's inherited RSS is invisible to rss_stat: the fork-time counter copies fire outside the child's context, and anon COW faults are counter-neutral, so a child that only touches inherited memory never reports anything on its own. A fork event carrying the parent pid lets consumers seed the child from the parent's last absolutes; exec and exit mark where the address space is replaced or torn down.
fork_idle's child only touches inherited memory (counter-neutral COW, no allocations), so its 32 MiB is observable exclusively through the fork-event seed; the parent samples /proc/<child>/status via a pipe handshake since any child-side allocation would emit a self-correcting absolute and defeat the test.
| self.attach_task_newtask()?; | ||
| self.attach_sched_process_exec()?; | ||
| self.attach_sched_process_exit()?; |
There was a problem hiding this comment.
Lifecycle attaches still abort
The rss_stat attach now warns and continues, but these new RSS lifecycle tracepoints still use ?. If a host can run the existing allocator probes but lacks or disables task:task_newtask, sched:sched_process_exec, or sched:sched_process_exit, attach_tracepoints() returns an error before the tracker starts. That keeps memory tracking unavailable on a host where only the RSS accounting side is unsupported. Make these lifecycle-only attaches best-effort as well, or gate RSS reconciliation on the lifecycle tracepoints that attach successfully.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/memtrack/src/ebpf/memtrack.rs
Line: 588-590
Comment:
**Lifecycle attaches still abort**
The `rss_stat` attach now warns and continues, but these new RSS lifecycle tracepoints still use `?`. If a host can run the existing allocator probes but lacks or disables `task:task_newtask`, `sched:sched_process_exec`, or `sched:sched_process_exit`, `attach_tracepoints()` returns an error before the tracker starts. That keeps memory tracking unavailable on a host where only the RSS accounting side is unsupported. Make these lifecycle-only attaches best-effort as well, or gate RSS reconciliation on the lifecycle tracepoints that attach successfully.
How can I resolve this? If you propose a fix, please make it concise.
Summary
Adds RSS (resident set size) collection to
memtrack, in two layers:kmem:rss_stattracepoint — absolute per-mm resident bytes (anon/file/shmem/swap), latest-wins.fentryhooks on the anon folio-rmap add/remove functions emit signed page-count deltas, so anon RSS can be rebuilt over time asΣ(add − remove) × PAGE_SIZE.The reconstruction is a total anon RSS delta-sum, not a per-vaddr resident map — the kernel remove hook (
folio_remove_rmap_ptes) carries no address, so removals can't be attributed to a vaddr (the add hooks' faulting vaddr is emitted for observability only).Commits
feat(memtrack): track RSS via kmem:rss_stat tracepoint— the baseline:EVENT_TYPE_RSScontract,MemtrackEventKind::Rss, parser arm, writer bench case, gated integration test.feat(memtrack): reconstruct anon RSS from gated folio rmap fentry hooks—EVENT_TYPE_RMAP_ANON+RmapAnonevent, fivefentryprograms (add_new / add_ptes / remove_ptes / remove_pmd / remove_pud), CO-RE folio helpers, and the load/attach gating.test(memtrack): validate anon RSS reconstruction against rss_stat— ramps anon RSS viammap/munmapand asserts the reconstructed estimate tracks therss_statMM_ANONPAGES peak within 25%.What's on by default vs gated
rss_stattracepoint: always on. EmittingRssevents is the intended new default behavior introduced by this change — the RSS tracepoint is not gated.RmapAnonfolio-rmapfentryprograms: off by default, gated behindCODSPEED_MEMTRACK_TRACK_RMAP=1. When the flag is unset they areset_autoload(false)before load and never attached, so:fentryBTF target would otherwise fail the whole load), and--mode memory) and out of the existing test suites — noRmapAnonevents are produced by default.Verification
Run in a privileged,
--pid=hostcontainer sharing the host kernel (7.0.12):real anon amplitude = 64 MiB, estimated peak = 64 MiB(ratio 1.00).rss_tests, flag unset): ✅ passes — noRmapAnonevents, folio-rmap programs stay unloaded.cargo fmt, andclippyclean.folio_*_rmap*functions verified to match theBPF_PROGarg layouts.Review notes (draft)
track_commandordering: the shared test helper spawns the child beforeenable()/track(root_pid). In practice the child'sfork→execve→ld.so→libc-initfar outlasts the two BPF-map updates, so tracking is armed before the workload allocates (both fixtures captured full event streams). Flagging in case we'd prefer a leading settle-usleepin the fixtures or an enable-before-spawn change in the helper.PAGE_SIZE: hardcoded to 4096 (correct on x86_64). On a 16K/64K-page arm64 runner the estimate would needsysconf(_SC_PAGESIZE);rss_statis already in bytes and unaffected. Happy to switch tosysconfif these tests run on arm64 CI.