Skip to content

Commit 410c2f1

Browse files
authored
Move observability-relevant structure fields to the top (#105271)
1 parent 9d35a71 commit 410c2f1

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)