Skip to content

Commit 31447b7

Browse files
committed
refactor: use instrument_hooks_callgrind_add_obj_skip from C API
Drop the locally-defined VG_USERREQ__ADD_OBJ_SKIP trapdoor and the Python-side realpath resolution. Both now live in instrument-hooks (65a7afb), so the binding just forwards to the shared helper. Refs COD-2658.
1 parent fc33d20 commit 31447b7

3 files changed

Lines changed: 23 additions & 55 deletions

File tree

src/pytest_codspeed/instruments/hooks/__init__.py

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self) -> None:
5252

5353
# Ignore libpython and python executable frames in callgrind so they
5454
# don't obfuscate the flamegraph.
55-
callgrind_skip_python_runtime()
55+
self._callgrind_skip_python_runtime()
5656

5757
def __del__(self):
5858
# Don't manually deinit - let the capsule destructor handle it
@@ -228,46 +228,21 @@ def collect_and_write_python_environment(self) -> None:
228228

229229
self.write_environment()
230230

231-
232-
def callgrind_add_obj_skip(path: str) -> None:
233-
"""Tell callgrind to skip the given object file (and its realpath).
234-
235-
The actual Valgrind client-request trapdoor lives in the C extension; this
236-
just resolves the realpath so callgrind's strcmp matches either form.
237-
"""
238-
if not path or not os.path.exists(path):
239-
return
240-
try:
241-
from . import dist_instrument_hooks # type: ignore
242-
except ImportError:
243-
return
244-
245-
dist_instrument_hooks.callgrind_add_obj_skip(path.encode())
246-
247-
# The dynamic loader maps the realpath (e.g. libpython3.12.so.1.0), and
248-
# callgrind stores that in obj_node->name. Skip both so the exact strcmp
249-
# matches regardless of which path callgrind sees.
250-
real = os.path.realpath(path)
251-
if real != path:
252-
dist_instrument_hooks.callgrind_add_obj_skip(real.encode())
253-
254-
255-
def callgrind_skip_python_runtime() -> None:
256-
"""Skip libpython and the python executable from callgrind measurement."""
257-
ldlibrary = sysconfig.get_config_var("LDLIBRARY")
258-
libdir = sysconfig.get_config_var("LIBDIR")
259-
libpython = next(
260-
(
261-
p
262-
for p in (
263-
os.path.join(libdir, ldlibrary) if ldlibrary and libdir else None,
264-
os.path.join(sys.prefix, "lib", ldlibrary) if ldlibrary else None,
265-
)
266-
if p and os.path.exists(p)
267-
),
268-
None,
269-
)
270-
if libpython:
271-
callgrind_add_obj_skip(libpython)
272-
273-
callgrind_add_obj_skip(sys.executable)
231+
def _callgrind_skip_python_runtime(self) -> None:
232+
"""Skip libpython and the python executable from callgrind measurement."""
233+
ldlibrary = sysconfig.get_config_var("LDLIBRARY")
234+
libdir = sysconfig.get_config_var("LIBDIR")
235+
libpython = next(
236+
(
237+
p
238+
for p in (
239+
os.path.join(libdir, ldlibrary) if ldlibrary and libdir else None,
240+
os.path.join(sys.prefix, "lib", ldlibrary) if ldlibrary else None,
241+
)
242+
if p and os.path.exists(p)
243+
),
244+
None,
245+
)
246+
if libpython:
247+
self._module.callgrind_add_obj_skip(libpython.encode())
248+
self._module.callgrind_add_obj_skip(sys.executable.encode())

src/pytest_codspeed/instruments/hooks/instrument_hooks_module.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
#define PY_SSIZE_T_CLEAN
22
#include <Python.h>
33
#include "core.h"
4-
#include "valgrind.h"
5-
6-
/* CodSpeed-specific Valgrind client request: tell callgrind to skip an
7-
* object file by path. Not present in upstream callgrind.h. */
8-
// TODO(COD-2654): Move this to instrument-hooks and just call it here
9-
#define VG_USERREQ__ADD_OBJ_SKIP 0x43540006
104

115
/* Capsule destructor for InstrumentHooks pointer */
126
static void instrument_hooks_capsule_destructor(PyObject *capsule) {
@@ -248,15 +242,14 @@ static PyObject *py_instrument_hooks_write_environment(PyObject *self, PyObject
248242
return PyLong_FromLong(result);
249243
}
250244

251-
/* callgrind_add_obj_skip(path: bytes) -> None
252-
* Outside Valgrind this expands to a nop, so it's safe on bare metal. */
245+
/* callgrind_add_obj_skip(path: bytes) -> int */
253246
static PyObject *py_callgrind_add_obj_skip(PyObject *self, PyObject *args) {
254247
const char *path;
255248
if (!PyArg_ParseTuple(args, "y", &path)) {
256249
return NULL;
257250
}
258-
VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ADD_OBJ_SKIP, path, 0, 0, 0, 0);
259-
Py_RETURN_NONE;
251+
uint8_t result = instrument_hooks_callgrind_add_obj_skip(path);
252+
return PyLong_FromLong(result);
260253
}
261254

262255
/* Method definitions */

0 commit comments

Comments
 (0)