Skip to content

Commit f9af502

Browse files
committed
Move observability-relevant structure fields to top
Some structures have fields that are used by out-of-process tools, like Austin. Having these fields defined after some more complex structures makes it hard to maintain these tools. With this change, we move the declaration of the most useful fields to the top of the structure definition. This reduces the amount of irrelevant information that the mentioned tools have to replicate to retrieve the actually useful data
1 parent 94a1eea commit f9af502

File tree

3 files changed

+63
-51
lines changed

3 files changed

+63
-51
lines changed

Include/internal/pycore_frame.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,20 @@ enum _frameowner {
4949
typedef struct _PyInterpreterFrame {
5050
PyCodeObject *f_code; /* Strong reference */
5151
struct _PyInterpreterFrame *previous;
52-
PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */
53-
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
54-
PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
55-
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
56-
PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */
5752
// NOTE: This is not necessarily the last instruction started in the given
5853
// frame. Rather, it is the code unit *prior to* the *next* instruction. For
5954
// example, it may be an inline CACHE entry, an instruction we just jumped
6055
// over, or (in the case of a newly-created frame) a totally invalid value:
6156
_Py_CODEUNIT *prev_instr;
57+
58+
/* The fields above this line are declared as early as possible to
59+
facilitate out-of-process observability tools. */
60+
61+
PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */
62+
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
63+
PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
64+
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
65+
PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */
6266
int stacktop; /* Offset of TOS from localsplus */
6367
/* The return_offset determines where a `RETURN` should go in the caller,
6468
* relative to `prev_instr`.

Include/internal/pycore_interp.h

+42-38
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,35 @@ struct _Py_long_state {
4747
The PyInterpreterState typedef is in Include/pytypedefs.h.
4848
*/
4949
struct _is {
50-
51-
struct _ceval_state ceval;
5250
PyInterpreterState *next;
5351

52+
int64_t id;
53+
int64_t id_refcount;
54+
int requires_idref;
55+
PyThread_type_lock id_mutex;
56+
57+
/* Has been initialized to a safe state.
58+
59+
In order to be effective, this must be set to 0 during or right
60+
after allocation. */
61+
int _initialized;
62+
int finalizing;
63+
5464
uint64_t monitoring_version;
5565
uint64_t last_restart_version;
5666

67+
/* The fields above this line are declared as early as possible to
68+
facilitate out-of-process observability tools. */
69+
70+
/* Set by Py_EndInterpreter().
71+
72+
Use _PyInterpreterState_GetFinalizing()
73+
and _PyInterpreterState_SetFinalizing()
74+
to access it, don't access it directly. */
75+
_Py_atomic_address _finalizing;
76+
77+
PyCodeObject *interpreter_trampoline;
78+
5779
struct pythreads {
5880
uint64_t next_unique_id;
5981
/* The linked list of threads, newest first. */
@@ -72,30 +94,22 @@ struct _is {
7294
Get runtime from tstate: tstate->interp->runtime. */
7395
struct pyruntimestate *runtime;
7496

75-
int64_t id;
76-
int64_t id_refcount;
77-
int requires_idref;
78-
PyThread_type_lock id_mutex;
79-
80-
/* Has been initialized to a safe state.
81-
82-
In order to be effective, this must be set to 0 during or right
83-
after allocation. */
84-
int _initialized;
85-
int finalizing;
86-
87-
/* Set by Py_EndInterpreter().
97+
struct _gc_runtime_state gc;
8898

89-
Use _PyInterpreterState_GetFinalizing()
90-
and _PyInterpreterState_SetFinalizing()
91-
to access it, don't access it directly. */
92-
_Py_atomic_address _finalizing;
99+
/* The following fields are here to avoid allocation during init.
100+
The data is exposed through PyInterpreterState pointer fields.
101+
These fields should not be accessed directly outside of init.
93102
94-
struct _obmalloc_state obmalloc;
103+
All other PyInterpreterState pointer fields are populated when
104+
needed and default to NULL.
95105
96-
struct _gc_runtime_state gc;
106+
For now there are some exceptions to that rule, which require
107+
allocation during init. These will be addressed on a case-by-case
108+
basis. Also see _PyRuntimeState regarding the various mutex fields.
109+
*/
97110

98-
struct _import_state imports;
111+
/* The per-interpreter GIL, which might not be used. */
112+
struct _gil_runtime_state _gil;
99113

100114
// Dictionary of the sys module
101115
PyObject *sysdict;
@@ -133,6 +147,12 @@ struct _is {
133147
struct _warnings_runtime_state warnings;
134148
struct atexit_state atexit;
135149

150+
struct _ceval_state ceval;
151+
152+
struct _obmalloc_state obmalloc;
153+
154+
struct _import_state imports;
155+
136156
PyObject *audit_hooks;
137157
PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS];
138158
PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS];
@@ -159,7 +179,6 @@ struct _is {
159179
struct ast_state ast;
160180
struct types_state types;
161181
struct callable_cache callable_cache;
162-
PyCodeObject *interpreter_trampoline;
163182
_PyOptimizerObject *optimizer;
164183
uint16_t optimizer_resume_threshold;
165184
uint16_t optimizer_backedge_threshold;
@@ -176,21 +195,6 @@ struct _is {
176195
struct _Py_interp_cached_objects cached_objects;
177196
struct _Py_interp_static_objects static_objects;
178197

179-
/* The following fields are here to avoid allocation during init.
180-
The data is exposed through PyInterpreterState pointer fields.
181-
These fields should not be accessed directly outside of init.
182-
183-
All other PyInterpreterState pointer fields are populated when
184-
needed and default to NULL.
185-
186-
For now there are some exceptions to that rule, which require
187-
allocation during init. These will be addressed on a case-by-case
188-
basis. Also see _PyRuntimeState regarding the various mutex fields.
189-
*/
190-
191-
/* The per-interpreter GIL, which might not be used. */
192-
struct _gil_runtime_state _gil;
193-
194198
/* the initial PyInterpreterState.threads.head */
195199
PyThreadState _initial_thread;
196200
};

Include/internal/pycore_runtime.h

+12-8
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,6 @@ typedef struct pyruntimestate {
8484
to access it, don't access it directly. */
8585
_Py_atomic_address _finalizing;
8686

87-
struct _pymem_allocators allocators;
88-
struct _obmalloc_global_state obmalloc;
89-
struct pyhash_runtime_state pyhash_state;
90-
struct _time_runtime_state time;
91-
struct _pythread_runtime_state threads;
92-
struct _signals_runtime_state signals;
93-
9487
struct pyinterpreters {
9588
PyThread_type_lock mutex;
9689
/* The linked list of interpreters, newest first. */
@@ -109,13 +102,24 @@ typedef struct pyruntimestate {
109102
using a Python int. */
110103
int64_t next_id;
111104
} interpreters;
105+
106+
unsigned long main_thread;
107+
108+
/* The fields above this line are declared as early as possible to
109+
facilitate out-of-process observability tools. */
110+
112111
// XXX Remove this field once we have a tp_* slot.
113112
struct _xidregistry {
114113
PyThread_type_lock mutex;
115114
struct _xidregitem *head;
116115
} xidregistry;
117116

118-
unsigned long main_thread;
117+
struct _pymem_allocators allocators;
118+
struct _obmalloc_global_state obmalloc;
119+
struct pyhash_runtime_state pyhash_state;
120+
struct _time_runtime_state time;
121+
struct _pythread_runtime_state threads;
122+
struct _signals_runtime_state signals;
119123

120124
/* Used for the thread state bound to the current thread. */
121125
Py_tss_t autoTSSkey;

0 commit comments

Comments
 (0)