perf(mallocfree): only poison freed V blocks at --sanity-level=3 - #31
Conversation
VG_(arena_free) filled every byte of every block V frees with 0xDD. It is a pure debugging aid for use-after-free bugs inside V itself, but it writes hundreds of MB per debuginfo-heavy run, including the parts of a block the owner never touched. Gate it behind --sanity-level=3, the threshold already used for expensive self-checks elsewhere in the codebase. This mirrors the malloc-side fill, which is already disabled by default. Callgrind output is byte-identical and the Callgrind regression suite passes unchanged.
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR reduces allocator overhead by limiting internal freed-block poisoning to sanity level 3 or above.
Confidence Score: 5/5The PR appears safe to merge with no actionable correctness or security issues identified. The changed condition only suppresses an optional internal payload poison at ordinary sanity levels; allocator checks and free-list operations rely on metadata and redzones rather than the poison bytes.
|
| Filename | Overview |
|---|---|
| coregrind/m_mallocfree.c | Gates the non-client arena free poison fill behind sanity level 3 without changing allocator metadata handling or client memory behavior. |
Reviews (1): Last reviewed commit: "perf(mallocfree): only poison freed V bl..." | Re-trigger Greptile
Summary
VG_(arena_free)overwrites every byte of every block Valgrind frees with0xDD. This is purely a debugging aid — it only makes use-after-free bugs inside V itself more likely to be noticed — but it costs real time on translation/debuginfo-heavy runs: the fill writes the whole block, including the parts the owner never used (e.g. an over-allocated XArray), so hundreds of MB of stores are issued per run just to be thrown away.This gates the fill behind
--sanity-level=3, the threshold already used in this codebase for expensive self-checks (m_signals.c,m_scheduler,aspacemgr). It mirrors the decision already made a few hundred lines above for the malloc-side fill, which upstream disables by default (if (0 && aid != VG_AR_CLIENT)) for the same reason.Client memory (
VG_AR_CLIENT) was already excluded from the fill, so nothing about how the client's heap is treated changes. Core developers can still get the poison fill with--sanity-level=3(and it is implicitly on at the level 4 that gdbserver monitor commands raise it to).Correctness
Verified against a baseline build of this branch's parent commit, both built from the same tree with the same configure flags:
callgrind.out, including thesummary:event counts) onecho, once the pid line and the install prefix baked intocob=are normalized.callgrind/tests, the same set CI runs).amd64/insn_*,gone_abrt_xml,sem,vcpu_bz2— they fail the same way without this change in this container, so they are not caused by it).Measured impact
Measured locally with
codspeed run -m walltimeon the exec-harness benchmarks (base and head runs interleaved twice, 25 rounds each, config generated withbench/generate_config.py):echo Hello, World!, no-inlineecho Hello, World!, inlinepython3 test.py, inlinellsc_tzconvert_bench 5000, no-inlineHead was faster than or equal to base on every benchmark in every one of the four runs, and a 30-pair alternating CPU-time A/B on
echo, no-inlinehad head faster in 25/30 pairs (median −1.5%).Caveat, stated plainly: the gain observed in this sandbox is ~1–1.5%, smaller than on the bare-metal
codspeed-macrorunners where this was originally profiled (there the win came mostly from kernel page-zeroing on first touch of the poisoned pages; in this virtualized container the minor-fault count is unchanged between the two builds, so only the raw store traffic is saved). The CodSpeed check on this PR runs on the macro runners and will record the real impact.Scope
One condition and a comment in
coregrind/m_mallocfree.c. No option, build, or output changes.