Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(alias)
STRUCT_FOR_ID(align)
STRUCT_FOR_ID(all)
STRUCT_FOR_ID(all_interpreters)
STRUCT_FOR_ID(all_threads)
STRUCT_FOR_ID(allow_code)
STRUCT_FOR_ID(alphabet)
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Modules/Setup
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ PYTHONPATH=$(COREPYTHONPATH)

#*shared*
#_ctypes_test _ctypes/_ctypes_test.c
#_remote_debugging _remote_debugging/module.c _remote_debugging/object_reading.c _remote_debugging/code_objects.c _remote_debugging/frames.c _remote_debugging/threads.c _remote_debugging/asyncio.c
#_remote_debugging _remote_debugging/module.c _remote_debugging/object_reading.c _remote_debugging/code_objects.c _remote_debugging/frames.c _remote_debugging/threads.c _remote_debugging/asyncio.c _remote_debugging/interpreters.c
#_testcapi _testcapimodule.c
#_testimportmultiple _testimportmultiple.c
#_testmultiphase _testmultiphase.c
Expand Down
2 changes: 1 addition & 1 deletion Modules/Setup.stdlib.in
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
@MODULE__PICKLE_TRUE@_pickle _pickle.c
@MODULE__QUEUE_TRUE@_queue _queuemodule.c
@MODULE__RANDOM_TRUE@_random _randommodule.c
@MODULE__REMOTE_DEBUGGING_TRUE@_remote_debugging _remote_debugging/module.c _remote_debugging/object_reading.c _remote_debugging/code_objects.c _remote_debugging/frames.c _remote_debugging/frame_cache.c _remote_debugging/threads.c _remote_debugging/asyncio.c _remote_debugging/binary_io_writer.c _remote_debugging/binary_io_reader.c _remote_debugging/subprocess.c
@MODULE__REMOTE_DEBUGGING_TRUE@_remote_debugging _remote_debugging/module.c _remote_debugging/object_reading.c _remote_debugging/code_objects.c _remote_debugging/frames.c _remote_debugging/frame_cache.c _remote_debugging/threads.c _remote_debugging/asyncio.c _remote_debugging/binary_io_writer.c _remote_debugging/binary_io_reader.c _remote_debugging/subprocess.c _remote_debugging/interpreters.c
@MODULE__STRUCT_TRUE@_struct _struct.c

# build supports subinterpreters
Expand Down
25 changes: 25 additions & 0 deletions Modules/_remote_debugging/_remote_debugging.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@ typedef struct {
size_t count;
} StackChunkList;

typedef struct {
proc_handle_t handle;
uintptr_t runtime_start_address;
struct _Py_DebugOffsets debug_offsets;
} RuntimeOffsets;
Copy link
Copy Markdown
Contributor Author

@sergey-miryanov sergey-miryanov Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it is a best name, but I'm out of ideas a bit.


/*
* Context for frame chain traversal operations.
*/
Expand Down Expand Up @@ -389,6 +395,14 @@ typedef int (*set_entry_processor_func)(
void *context
);

typedef int (*interpreter_processor_func)(
RuntimeOffsets *offsets,
uintptr_t interpreter_state_addr,
unsigned long iid,
void *context
);


/* ============================================================================
* STRUCTSEQ DESCRIPTORS (extern declarations)
* ============================================================================ */
Expand Down Expand Up @@ -586,6 +600,17 @@ extern void _Py_RemoteDebug_InitThreadsState(RemoteUnwinderObject *unwinder, _Py
extern int _Py_RemoteDebug_StopAllThreads(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_ThreadsState *st);
extern void _Py_RemoteDebug_ResumeAllThreads(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_ThreadsState *st);

/* ============================================================================
* INTERPRETER FUNCTION DECLARATIONS
* ============================================================================ */

extern int
iterate_interpreters(
RuntimeOffsets *offsets,
interpreter_processor_func processor,
void *context
);

/* ============================================================================
* ASYNCIO FUNCTION DECLARATIONS
* ============================================================================ */
Expand Down
78 changes: 77 additions & 1 deletion Modules/_remote_debugging/clinic/module.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

143 changes: 143 additions & 0 deletions Modules/_remote_debugging/gc_stats.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/******************************************************************************
* Remote Debugging Module - GC Stats Functions
*
* This file contains function for read GC stats from interpreter state.
******************************************************************************/

#ifndef Py_REMOTE_DEBUGGING_GC_STATS_H
#define Py_REMOTE_DEBUGGING_GC_STATS_H

#ifdef __cplusplus
extern "C" {
#endif

#include "_remote_debugging.h"

static int
read_gc_stats(struct gc_stats *stats, unsigned long iid, PyObject *result)
{
#define ADD_LOCAL_ULONG(name) do { \
val = PyLong_FromUnsignedLong(name); \
if (!val || PyDict_SetItemString(item, #name, val) < 0) { \
goto error; \
} \
Py_DECREF(val); \
} while(0)

#define ADD_STATS_SSIZE(name) do { \
val = PyLong_FromSsize_t(stats_item->name); \
if (!val || PyDict_SetItemString(item, #name, val) < 0) { \
goto error; \
} \
Py_DECREF(val); \
} while(0)

#define ADD_STATS_INT64(name) do { \
val = PyLong_FromInt64(stats_item->name); \
if (!val || PyDict_SetItemString(item, #name, val) < 0) { \
goto error; \
} \
Py_DECREF(val); \
} while(0)

#define ADD_STATS_DOUBLE(name) do { \
val = PyFloat_FromDouble(stats_item->name); \
if (!val || PyDict_SetItemString(item, #name, val) < 0) { \
goto error; \
} \
Py_DECREF(val); \
} while(0)

PyObject *item = NULL;
PyObject *val = NULL;

for(unsigned long gen = 0; gen < NUM_GENERATIONS; gen++) {
struct gc_generation_stats *items;
int size;
if (gen == 0) {
items = (struct gc_generation_stats *)stats->young.items;
size = GC_YOUNG_STATS_SIZE;
}
else {
items = (struct gc_generation_stats *)stats->old[gen-1].items;
size = GC_OLD_STATS_SIZE;
}
for(int i = 0; i < size; i++, items++) {
struct gc_generation_stats *stats_item = items;
item = PyDict_New();
if (item == NULL) {
goto error;
}

ADD_LOCAL_ULONG(gen);
ADD_LOCAL_ULONG(iid);

ADD_STATS_INT64(ts_start);
ADD_STATS_INT64(ts_stop);
ADD_STATS_SSIZE(heap_size);
ADD_STATS_SSIZE(work_to_do);
ADD_STATS_SSIZE(collections);
ADD_STATS_SSIZE(object_visits);
ADD_STATS_SSIZE(collected);
ADD_STATS_SSIZE(uncollectable);
ADD_STATS_SSIZE(candidates);
ADD_STATS_SSIZE(objects_transitively_reachable);
ADD_STATS_SSIZE(objects_not_transitively_reachable);

ADD_STATS_DOUBLE(duration);
val = NULL;

int rc = PyList_Append(result, item);
Py_CLEAR(item);
if (rc < 0) {
goto error;
}
}
}

#undef ADD_LOCAL_ULONG
#undef ADD_STATS_SSIZE
#undef ADD_STATS_INT64
#undef ADD_STATS_DOUBLE

return 0;

error:
Py_XDECREF(val);
Py_XDECREF(item);

return -1;
}

static int
get_gc_stats_from_interpreter_state(RuntimeOffsets *offsets,
uintptr_t interpreter_state_addr,
unsigned long iid,
void *context)
{
struct gc_stats stats;
uintptr_t gc_stats_address = interpreter_state_addr
+ offsets->debug_offsets.interpreter_state.gc
+ offsets->debug_offsets.gc.generation_stats;
uint64_t gc_stats_size = offsets->debug_offsets.gc.generation_stats_size;
if (_Py_RemoteDebug_ReadRemoteMemory(&offsets->handle,
gc_stats_address,
gc_stats_size,
&stats) < 0) {
PyErr_SetString(PyExc_RuntimeError, "Failed to read GC state");
return -1;
}

PyObject *result = context;
if (read_gc_stats(&stats, iid, result) < 0) {
return -1;
}

return 0;
}

#ifdef __cplusplus
}
#endif

#endif /* Py_REMOTE_DEBUGGING_GC_STATS_H */
Loading
Loading