-
-
Notifications
You must be signed in to change notification settings - Fork 34.6k
Expand file tree
/
Copy pathgc_stats.c
More file actions
154 lines (133 loc) · 4.9 KB
/
gc_stats.c
File metadata and controls
154 lines (133 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/******************************************************************************
* Remote Debugging Module - GC Stats Functions
*
* This file contains functions for reading GC stats from interpreter state.
******************************************************************************/
#include "gc_stats.h"
typedef struct {
PyObject *result;
PyTypeObject *gc_stats_info_type;
bool all_interpreters;
} GetGCStatsContext;
static int
read_gc_stats(struct gc_stats *stats, int64_t iid, PyObject *result,
PyTypeObject *gc_stats_info_type)
{
#define SET_FIELD(converter, expr) do { \
PyObject *value = converter(expr); \
if (value == NULL) { \
goto error; \
} \
PyStructSequence_SetItem(item, field++, value); \
} while (0)
PyObject *item = 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++) {
item = PyStructSequence_New(gc_stats_info_type);
if (item == NULL) {
goto error;
}
Py_ssize_t field = 0;
SET_FIELD(PyLong_FromUnsignedLong, gen);
SET_FIELD(PyLong_FromInt64, iid);
SET_FIELD(PyLong_FromInt64, items->ts_start);
SET_FIELD(PyLong_FromInt64, items->ts_stop);
SET_FIELD(PyLong_FromSsize_t, items->collections);
SET_FIELD(PyLong_FromSsize_t, items->collected);
SET_FIELD(PyLong_FromSsize_t, items->uncollectable);
SET_FIELD(PyLong_FromSsize_t, items->candidates);
SET_FIELD(PyLong_FromSsize_t, items->heap_size);
SET_FIELD(PyFloat_FromDouble, items->duration);
int rc = PyList_Append(result, item);
Py_CLEAR(item);
if (rc < 0) {
goto error;
}
}
}
#undef SET_FIELD
return 0;
error:
Py_XDECREF(item);
return -1;
}
static int
get_gc_stats_from_interpreter_state(RuntimeOffsets *offsets,
uintptr_t interpreter_state_addr,
int64_t iid,
void *context)
{
GetGCStatsContext *ctx = (GetGCStatsContext *)context;
if (!ctx->all_interpreters && iid > 0) {
return 0;
}
uintptr_t gc_stats_addr = 0;
uintptr_t gc_stats_pointer_address = interpreter_state_addr
+ offsets->debug_offsets.interpreter_state.gc
+ offsets->debug_offsets.gc.generation_stats;
if (_Py_RemoteDebug_ReadRemoteMemory(&offsets->handle,
gc_stats_pointer_address,
sizeof(gc_stats_addr),
&gc_stats_addr) < 0) {
set_exception_cause(offsets, PyExc_RuntimeError, "Failed to read GC state address");
return -1;
}
if (gc_stats_addr == 0) {
PyErr_SetString(PyExc_RuntimeError, "GC state address is NULL");
return -1;
}
struct gc_stats stats;
if (_Py_RemoteDebug_ReadRemoteMemory(&offsets->handle,
gc_stats_addr,
sizeof(stats),
&stats) < 0) {
set_exception_cause(offsets, PyExc_RuntimeError, "Failed to read GC state");
return -1;
}
if (read_gc_stats(&stats, iid, ctx->result,
ctx->gc_stats_info_type) < 0) {
set_exception_cause(offsets, PyExc_RuntimeError, "Failed to populate GC stats result");
return -1;
}
return 0;
}
PyObject *
get_gc_stats(RuntimeOffsets *offsets, bool all_interpreters,
PyTypeObject *gc_stats_info_type)
{
uint64_t gc_stats_size = offsets->debug_offsets.gc.generation_stats_size;
if (gc_stats_size != sizeof(struct gc_stats)) {
PyErr_Format(PyExc_RuntimeError,
"Remote gc_stats size (%llu) does not match "
"local size (%zu)",
(unsigned long long)gc_stats_size,
sizeof(struct gc_stats));
set_exception_cause(offsets, PyExc_RuntimeError, "Remote gc_stats size mismatch");
return NULL;
}
PyObject *result = PyList_New(0);
if (result == NULL) {
return NULL;
}
GetGCStatsContext ctx = {
.result = result,
.gc_stats_info_type = gc_stats_info_type,
.all_interpreters = all_interpreters,
};
if (iterate_interpreters(offsets, get_gc_stats_from_interpreter_state,
&ctx) < 0) {
Py_CLEAR(result);
return NULL;
}
return result;
}