Skip to content

Commit f186d3f

Browse files
committed
profiling(gecko): retrieve main thread id directly from interpreter state
Signed-off-by: Sofia Donato Ferreira <flowlnlnln@gmail.com>
1 parent d9b0a79 commit f186d3f

7 files changed

Lines changed: 27 additions & 14 deletions

File tree

Lib/profiling/sampling/gecko_collector.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,7 @@ def collect(self, stack_frames, timestamps_us=None):
171171

172172
# Process threads
173173
for interpreter_info in stack_frames:
174-
# Since 'threads' is in order from newest to oldest,
175-
# we know the first thread must be the main thread.
176-
main_tid = None
177-
if len(interpreter_info.threads) != 0:
178-
main_tid = interpreter_info.threads[-1].thread_id
174+
main_tid = interpreter_info.main_thread_id
179175
for thread_info in interpreter_info.threads:
180176
frames = filter_internal_frames(thread_info.frame_info)
181177
tid = thread_info.thread_id

Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ def make_thread(thread_id, frames, status=0):
4747
return ThreadInfo((thread_id, status, frames))
4848

4949

50-
def make_interpreter(interp_id, threads):
50+
def make_interpreter(interp_id, threads, main_thread_id=0):
5151
"""Create an InterpreterInfo struct sequence."""
52-
return InterpreterInfo((interp_id, threads))
52+
return InterpreterInfo((interp_id, main_thread_id, threads))
5353

5454

5555
def extract_lineno(location):

Modules/_remote_debugging/_remote_debugging.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,8 @@ extern PyObject* unwind_stack_for_thread(
575575
RemoteUnwinderObject *unwinder,
576576
uintptr_t *current_tstate,
577577
uintptr_t gil_holder_tstate,
578-
uintptr_t gc_frame
578+
uintptr_t gc_frame,
579+
uint64_t *current_thread_id
579580
);
580581

581582
/* Thread stopping functions (for blocking mode) */

Modules/_remote_debugging/binary_io_reader.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,7 @@ build_sample_list(RemoteDebuggingState *state, BinaryReader *reader,
828828
goto error;
829829
}
830830
PyStructSequence_SetItem(interp_info, 0, iid);
831-
PyStructSequence_SetItem(interp_info, 1, thread_list);
831+
PyStructSequence_SetItem(interp_info, 2, thread_list);
832832
thread_list = NULL;
833833

834834
sample_list = PyList_New(1);

Modules/_remote_debugging/binary_io_writer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,7 @@ binary_writer_write_sample(BinaryWriter *writer, PyObject *stack_frames, uint64_
10081008
PyObject *interp_info = PyList_GET_ITEM(stack_frames, i);
10091009

10101010
PyObject *interp_id_obj = PyStructSequence_GET_ITEM(interp_info, 0);
1011-
PyObject *threads = PyStructSequence_GET_ITEM(interp_info, 1);
1011+
PyObject *threads = PyStructSequence_GET_ITEM(interp_info, 2);
10121012

10131013
unsigned long interp_id_long = PyLong_AsUnsignedLong(interp_id_obj);
10141014
if (interp_id_long == (unsigned long)-1 && PyErr_Occurred()) {

Modules/_remote_debugging/module.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ PyStructSequence_Desc ThreadInfo_desc = {
106106
// InterpreterInfo structseq type
107107
static PyStructSequence_Field InterpreterInfo_fields[] = {
108108
{"interpreter_id", "Interpreter ID"},
109+
{"main_thread_id", "Main thread ID"},
109110
{"threads", "List of threads in this interpreter"},
110111
{NULL}
111112
};
@@ -114,7 +115,7 @@ PyStructSequence_Desc InterpreterInfo_desc = {
114115
"_remote_debugging.InterpreterInfo",
115116
"Information about an interpreter",
116117
InterpreterInfo_fields,
117-
2
118+
3
118119
};
119120

120121
// AwaitedInfo structseq type
@@ -583,11 +584,19 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self
583584
current_tstate = self->tstate_addr;
584585
}
585586

587+
// Acquire main thread state information
588+
uintptr_t main_thread_tstate = GET_MEMBER(uintptr_t, interp_state_buffer,
589+
self->debug_offsets.interpreter_state.threads_main);
590+
591+
PyObject *main_thread_id = NULL;
592+
593+
uint64_t prev_thread_id = 0;
586594
while (current_tstate != 0) {
587595
uintptr_t prev_tstate = current_tstate;
588596
PyObject* frame_info = unwind_stack_for_thread(self, &current_tstate,
589597
gil_holder_tstate,
590-
gc_frame);
598+
gc_frame,
599+
&prev_thread_id);
591600
if (!frame_info) {
592601
// Check if this was an intentional skip due to mode-based filtering
593602
if ((self->mode == PROFILING_MODE_CPU || self->mode == PROFILING_MODE_GIL ||
@@ -613,6 +622,10 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self
613622
goto exit;
614623
}
615624

625+
if (prev_tstate == main_thread_tstate) {
626+
main_thread_id = PyLong_FromUnsignedLongLong(prev_thread_id);
627+
}
628+
616629
if (PyList_Append(interpreter_threads, frame_info) == -1) {
617630
Py_DECREF(frame_info);
618631
Py_DECREF(interpreter_threads);
@@ -648,7 +661,8 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self
648661
}
649662

650663
PyStructSequence_SetItem(interpreter_info, 0, interp_id); // steals reference
651-
PyStructSequence_SetItem(interpreter_info, 1, interpreter_threads); // steals reference
664+
PyStructSequence_SetItem(interpreter_info, 1, main_thread_id); // steals reference
665+
PyStructSequence_SetItem(interpreter_info, 2, interpreter_threads); // steals reference
652666

653667
// Add this interpreter to the result list
654668
if (PyList_Append(result, interpreter_info) == -1) {

Modules/_remote_debugging/threads.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ unwind_stack_for_thread(
291291
RemoteUnwinderObject *unwinder,
292292
uintptr_t *current_tstate,
293293
uintptr_t gil_holder_tstate,
294-
uintptr_t gc_frame
294+
uintptr_t gc_frame,
295+
uint64_t *current_tid
295296
) {
296297
PyObject *frame_info = NULL;
297298
PyObject *thread_id = NULL;
@@ -309,6 +310,7 @@ unwind_stack_for_thread(
309310
STATS_ADD(unwinder, memory_bytes_read, unwinder->debug_offsets.thread_state.size);
310311

311312
long tid = GET_MEMBER(long, ts, unwinder->debug_offsets.thread_state.native_thread_id);
313+
*current_tid = tid;
312314

313315
// Read GC collecting state from the interpreter (before any skip checks)
314316
uintptr_t interp_addr = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.interp);

0 commit comments

Comments
 (0)