perf python: Update callchain stubs and session thread lookup

Update pyrf_session__find_thread() in util/python.c to accept an
optional tid parameter (defaulting to pid) and return None instead of
raising TypeError when a thread is not found in the session machines.

Update perf.pyi to match:
- Set session.find_thread() signature to (pid: int, tid: int = -1) ->
  Optional[thread].
- Update callchain_node.symbol and callchain_node.dso to str (the C
  getters return "[unknown]" fallback strings rather than None) and add
  __iter__() to callchain.

Also update treport.py to handle Optional[thread] returned by
session.find_thread().

Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2026-09-25 23:19:29 -07:00 committed by Arnaldo Carvalho de Melo
parent c4925cc8b8
commit 514ecdfd00
3 changed files with 16 additions and 12 deletions

View File

@ -332,13 +332,14 @@ class branch_stack:
class callchain_node:
"""Represents a frame in the callchain."""
ip: int
symbol: Optional[str]
dso: Optional[str]
symbol: str
dso: str
class callchain:
"""Sequence of callchain frames."""
def __len__(self) -> int: ...
def __getitem__(self, index: int) -> callchain_node: ...
def __iter__(self) -> Iterator[callchain_node]: ...
class stat_event(_sample_members):
"""Represents a stat event from perf."""
@ -453,7 +454,7 @@ class session:
def process_events(self) -> None:
"""Process all events in the session."""
...
def find_thread(self, pid: int) -> thread:
def find_thread(self, pid: int, tid: int = -1, /) -> Optional[thread]:
"""Returns the thread associated with a pid."""
...

View File

@ -92,7 +92,7 @@ class ProfileNode:
try:
assert session
thread = session.find_thread(sample.sample_tid)
comm = thread.comm()
comm = (thread.comm() if thread else None) or f"unknown ({pid})"
except Exception:
comm = f"unknown ({pid})"

View File

@ -3915,26 +3915,29 @@ static PyObject *pyrf_session__find_thread(struct pyrf_session *psession, PyObje
struct machine *machine;
struct thread *thread = NULL;
PyObject *result;
int pid;
int pid, tid = -1;
CHECK_INITIALIZED(psession->session, "session");
if (!PyArg_ParseTuple(args, "i", &pid))
if (!PyArg_ParseTuple(args, "i|i", &pid, &tid))
return NULL;
if (tid == -1)
tid = pid;
/* Look up the thread in the host machine first, then fall back to guest machines. */
machine = &psession->session->machines.host;
thread = machine__find_thread(machine, pid, pid);
thread = machine__find_thread(machine, pid, tid);
if (!thread) {
machine = perf_session__find_machine(psession->session, pid);
if (machine)
thread = machine__find_thread(machine, pid, pid);
thread = machine__find_thread(machine, pid, tid);
}
if (!thread) {
PyErr_Format(PyExc_TypeError, "Failed to find thread %d", pid);
return NULL;
}
/* Return None rather than raising TypeError when a PID/TID is not known. */
if (!thread)
Py_RETURN_NONE;
result = pyrf_thread__from_thread(thread);
thread__put(thread);
return result;