feat: allow skipping objects at runtime#9
Conversation
not-matthias
commented
May 14, 2026
- fix(debuginfo): resolve addresses in additional R-E LOAD segments
- feat(callgrind): add CALLGRIND_ADD_OBJ_SKIP client request
- test(callgrind): add Python regression test for runtime obj-skip
VG_(find_DebugInfo) used only di->text_avma/text_size for address→DI lookup, which covers the section named ".text" — not the other executable sections (.text.warm, .text.cold, .bolt.org.text) that BOLT-optimized binaries place in a separate R-E PT_LOAD segment. Addresses in that second segment fell through to ob=??? even though the address-space manager already knew they were backed by the same file. Fall back to VG_(am_find_nsegment) and match the segment's filename against debugInfo_list. Reproduced on cpython-3.14 standalone (uv's distribution): obj-skip now catches py_trampoline_evaluator, _PyFunction_Vectorcall.cold, and other functions that previously escaped via ob=???.
Add a trapdoor that lets the client register obj-skip paths at runtime, alongside the existing cmdline --obj-skip. Useful when the skip target isn't known statically (e.g. discovering the libpython path at Python startup). Extract CLG_(add_obj_to_skip) so the cmdline parser and the new client request share the same append-to-realloc'd-array logic.
End-to-end test for CALLGRIND_ADD_OBJ_SKIP using the canonical flow: start with --instr-atstart=no, register the libpython path via the trapdoor, then turn instrumentation on so the skip applies from the first instrumented BB.
Merging this PR will degrade performance by 24.68%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | test_valgrind[valgrind-3.25.1, python3 testdata/test.py, full-no-inline] |
5.2 s | 7 s | -24.68% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing cod-2654-flamegraph-doesnt-work-on-valgrind (fe0dbfc) with master (022ccc3)
Footnotes
-
8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
There was a problem hiding this comment.
Pull request overview
This PR adds runtime object skipping support to Callgrind and adjusts debuginfo lookup so additional executable LOAD segments can be associated with their object file.
Changes:
- Adds
CALLGRIND_ADD_OBJ_SKIPclient request and routes it through Callgrind option storage. - Adds a Python/ctypes regression test and C shim for runtime object skipping.
- Adds a debuginfo fallback that matches mapped addresses to
DebugInfoby filename.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
coregrind/m_debuginfo/debuginfo.c |
Adds fallback DebugInfo lookup via address-space segment filename. |
callgrind/callgrind.h |
Defines the new runtime object-skip client request macro. |
callgrind/main.c |
Handles the new client request. |
callgrind/clo.c |
Refactors object-skip insertion into a reusable helper. |
callgrind/global.h |
Exposes the object-skip helper. |
callgrind/tests/Makefile.am |
Adds and builds the runtime object-skip Python test assets. |
callgrind/tests/runtime_obj_skip_py.vgtest |
Adds the regression test driver. |
callgrind/tests/runtime_obj_skip_py.py |
Resolves Python-related objects and issues runtime skip requests. |
callgrind/tests/runtime_obj_skip_py_shim.c |
Provides ctypes-callable wrappers for Callgrind client requests. |
callgrind/tests/runtime_obj_skip_py.stderr.exp |
Adds expected stderr output. |
callgrind/tests/runtime_obj_skip_py.post.exp |
Adds expected post-check output. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| a DebugInfo by filename. */ | ||
| if (eq_DiEpoch(ep, VG_(current_DiEpoch)())) { | ||
| const NSegment* seg = VG_(am_find_nsegment)(a); | ||
| const HChar* filename; | ||
| if (seg != NULL && (filename = VG_(am_get_filename)(seg)) != NULL) { | ||
| for (di = debugInfo_list; di != NULL; di = di->next) { | ||
| if (!is_DI_valid_for_epoch(di, ep)) | ||
| continue; | ||
| if (di->fsm.filename != NULL | ||
| && 0 == VG_(strcmp)(di->fsm.filename, filename)) { | ||
| return di; | ||
| } | ||
| } |
art049
left a comment
There was a problem hiding this comment.
LGTM for the trapdoor.
We'll have to do a second pass on the BOLT handling to make sure we can release this without any regresions