Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions Include/internal/pycore_debug_offsets.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ typedef struct _Py_DebugOffsets {
uint64_t size;
uint64_t collecting;
uint64_t frame;
uint64_t generation_stats_size;
uint64_t generation_stats;
} gc;

// Generator object offset;
Expand Down Expand Up @@ -373,6 +375,8 @@ typedef struct _Py_DebugOffsets {
.size = sizeof(struct _gc_runtime_state), \
.collecting = offsetof(struct _gc_runtime_state, collecting), \
.frame = offsetof(struct _gc_runtime_state, frame), \
.generation_stats_size = sizeof(struct gc_stats), \
.generation_stats = offsetof(struct _gc_runtime_state, generation_stats), \
}, \
.gen_object = { \
.size = sizeof(PyGenObject), \
Expand Down
54 changes: 41 additions & 13 deletions Include/internal/pycore_interp_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,31 +177,54 @@ struct gc_generation {
generations */
};

struct gc_collection_stats {
/* number of collected objects */
Py_ssize_t collected;
/* total number of uncollectable objects (put into gc.garbage) */
Py_ssize_t uncollectable;
// Total number of objects considered for collection and traversed:
Py_ssize_t candidates;
// Duration of the collection in seconds:
double duration;
};

/* Running stats per generation */
struct gc_generation_stats {
PyTime_t ts_start;
PyTime_t ts_stop;

/* heap_size on the start of the collection */
Py_ssize_t heap_size;

/* work_to_do on the start of the collection */
Py_ssize_t work_to_do;

/* total number of collections */
Py_ssize_t collections;

/* total number of visited objects */
Py_ssize_t object_visits;

/* total number of collected objects */
Py_ssize_t collected;
/* total number of uncollectable objects (put into gc.garbage) */
Py_ssize_t uncollectable;
// Total number of objects considered for collection and traversed:
Py_ssize_t candidates;
// Duration of the collection in seconds:

Py_ssize_t objects_transitively_reachable;
Py_ssize_t objects_not_transitively_reachable;

// Total duration of the collection in seconds:
double duration;
};

#ifdef Py_GIL_DISABLED
#define GC_YOUNG_STATS_SIZE 1
#define GC_OLD_STATS_SIZE 1
#else
#define GC_YOUNG_STATS_SIZE 11
#define GC_OLD_STATS_SIZE 3
#endif
struct gc_young_stats_buffer {
struct gc_generation_stats items[GC_YOUNG_STATS_SIZE];
int8_t index;
};

struct gc_old_stats_buffer {
struct gc_generation_stats items[GC_OLD_STATS_SIZE];
int8_t index;
};

enum _GCPhase {
GC_PHASE_MARK = 0,
GC_PHASE_COLLECT = 1
Expand All @@ -211,6 +234,11 @@ enum _GCPhase {
signature of gc.collect and change the size of PyStats.gc_stats */
#define NUM_GENERATIONS 3

struct gc_stats {
struct gc_young_stats_buffer young;
struct gc_old_stats_buffer old[2];
};

struct _gc_runtime_state {
/* Is automatic collection enabled? */
int enabled;
Expand All @@ -220,7 +248,7 @@ struct _gc_runtime_state {
struct gc_generation old[2];
/* a permanent generation which won't be collected */
struct gc_generation permanent_generation;
struct gc_generation_stats generation_stats[NUM_GENERATIONS];
struct gc_stats generation_stats;
/* true if we are currently running the collector */
int collecting;
// The frame that started the current collection. It might be NULL even when
Expand Down
6 changes: 3 additions & 3 deletions Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,9 @@ gc_get_stats_impl(PyObject *module)
/* To get consistent values despite allocations while constructing
the result list, we use a snapshot of the running stats. */
GCState *gcstate = get_gc_state();
for (i = 0; i < NUM_GENERATIONS; i++) {
stats[i] = gcstate->generation_stats[i];
}
stats[0] = gcstate->generation_stats.young.items[gcstate->generation_stats.young.index];
stats[1] = gcstate->generation_stats.old[0].items[gcstate->generation_stats.old[0].index];
stats[2] = gcstate->generation_stats.old[1].items[gcstate->generation_stats.old[1].index];

PyObject *result = PyList_New(0);
if (result == NULL)
Expand Down
Loading
Loading