Skip to content

Commit bc8cdf8

Browse files
gh-81057: Move Ceval Trampoline Globals to _PyRuntimeState (gh-100083)
#81057
1 parent 1cfa704 commit bc8cdf8

File tree

9 files changed

+125
-84
lines changed

9 files changed

+125
-84
lines changed

Include/internal/pycore_ceval_state.h

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#ifndef Py_INTERNAL_CEVAL_STATE_H
2+
#define Py_INTERNAL_CEVAL_STATE_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
12+
#include "pycore_atomic.h" /* _Py_atomic_address */
13+
#include "pycore_gil.h" // struct _gil_runtime_state
14+
15+
16+
typedef enum {
17+
PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state
18+
PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized
19+
PERF_STATUS_OK = 1, // Perf trampoline is ready to be executed
20+
} perf_status_t;
21+
22+
23+
#ifdef PY_HAVE_PERF_TRAMPOLINE
24+
struct code_arena_st;
25+
26+
struct trampoline_api_st {
27+
void* (*init_state)(void);
28+
void (*write_state)(void* state, const void *code_addr,
29+
unsigned int code_size, PyCodeObject* code);
30+
int (*free_state)(void* state);
31+
void *state;
32+
};
33+
#endif
34+
35+
struct _ceval_runtime_state {
36+
struct {
37+
#ifdef PY_HAVE_PERF_TRAMPOLINE
38+
perf_status_t status;
39+
Py_ssize_t extra_code_index;
40+
struct code_arena_st *code_arena;
41+
struct trampoline_api_st trampoline_api;
42+
FILE *map_file;
43+
#else
44+
int _not_used;
45+
#endif
46+
} perf;
47+
/* Request for checking signals. It is shared by all interpreters (see
48+
bpo-40513). Any thread of any interpreter can receive a signal, but only
49+
the main thread of the main interpreter can handle signals: see
50+
_Py_ThreadCanHandleSignals(). */
51+
_Py_atomic_int signals_pending;
52+
struct _gil_runtime_state gil;
53+
};
54+
55+
#ifdef PY_HAVE_PERF_TRAMPOLINE
56+
# define _PyEval_RUNTIME_PERF_INIT \
57+
{ \
58+
.status = PERF_STATUS_NO_INIT, \
59+
.extra_code_index = -1, \
60+
}
61+
#else
62+
# define _PyEval_RUNTIME_PERF_INIT {0}
63+
#endif
64+
65+
66+
struct _pending_calls {
67+
int busy;
68+
PyThread_type_lock lock;
69+
/* Request for running pending calls. */
70+
_Py_atomic_int calls_to_do;
71+
/* Request for looking at the `async_exc` field of the current
72+
thread state.
73+
Guarded by the GIL. */
74+
int async_exc;
75+
#define NPENDINGCALLS 32
76+
struct {
77+
int (*func)(void *);
78+
void *arg;
79+
} calls[NPENDINGCALLS];
80+
int first;
81+
int last;
82+
};
83+
84+
struct _ceval_state {
85+
int recursion_limit;
86+
/* This single variable consolidates all requests to break out of
87+
the fast path in the eval loop. */
88+
_Py_atomic_int eval_breaker;
89+
/* Request for dropping the GIL */
90+
_Py_atomic_int gil_drop_request;
91+
/* The GC is ready to be executed */
92+
_Py_atomic_int gc_scheduled;
93+
struct _pending_calls pending;
94+
};
95+
96+
97+
#ifdef __cplusplus
98+
}
99+
#endif
100+
#endif /* !Py_INTERNAL_CEVAL_STATE_H */

Include/internal/pycore_interp.h

+1-31
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern "C" {
1212

1313
#include "pycore_atomic.h" // _Py_atomic_address
1414
#include "pycore_ast_state.h" // struct ast_state
15+
#include "pycore_ceval_state.h" // struct _ceval_state
1516
#include "pycore_code.h" // struct callable_cache
1617
#include "pycore_context.h" // struct _Py_context_state
1718
#include "pycore_dict_state.h" // struct _Py_dict_state
@@ -28,37 +29,6 @@ extern "C" {
2829
#include "pycore_warnings.h" // struct _warnings_runtime_state
2930

3031

31-
struct _pending_calls {
32-
int busy;
33-
PyThread_type_lock lock;
34-
/* Request for running pending calls. */
35-
_Py_atomic_int calls_to_do;
36-
/* Request for looking at the `async_exc` field of the current
37-
thread state.
38-
Guarded by the GIL. */
39-
int async_exc;
40-
#define NPENDINGCALLS 32
41-
struct {
42-
int (*func)(void *);
43-
void *arg;
44-
} calls[NPENDINGCALLS];
45-
int first;
46-
int last;
47-
};
48-
49-
struct _ceval_state {
50-
int recursion_limit;
51-
/* This single variable consolidates all requests to break out of
52-
the fast path in the eval loop. */
53-
_Py_atomic_int eval_breaker;
54-
/* Request for dropping the GIL */
55-
_Py_atomic_int gil_drop_request;
56-
/* The GC is ready to be executed */
57-
_Py_atomic_int gc_scheduled;
58-
struct _pending_calls pending;
59-
};
60-
61-
6232
// atexit state
6333
typedef struct {
6434
PyObject *func;

Include/internal/pycore_runtime.h

+1-10
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ extern "C" {
99
#endif
1010

1111
#include "pycore_atomic.h" /* _Py_atomic_address */
12+
#include "pycore_ceval_state.h" // struct _ceval_runtime_state
1213
#include "pycore_dict_state.h" // struct _Py_dict_runtime_state
1314
#include "pycore_dtoa.h" // struct _dtoa_runtime_state
1415
#include "pycore_floatobject.h" // struct _Py_float_runtime_state
1516
#include "pycore_function.h" // struct _func_runtime_state
16-
#include "pycore_gil.h" // struct _gil_runtime_state
1717
#include "pycore_global_objects.h" // struct _Py_global_objects
1818
#include "pycore_import.h" // struct _import_runtime_state
1919
#include "pycore_interp.h" // PyInterpreterState
@@ -31,15 +31,6 @@ struct _getargs_runtime_state {
3131

3232
/* ceval state */
3333

34-
struct _ceval_runtime_state {
35-
/* Request for checking signals. It is shared by all interpreters (see
36-
bpo-40513). Any thread of any interpreter can receive a signal, but only
37-
the main thread of the main interpreter can handle signals: see
38-
_Py_ThreadCanHandleSignals(). */
39-
_Py_atomic_int signals_pending;
40-
struct _gil_runtime_state gil;
41-
};
42-
4334
/* GIL state */
4435

4536
struct _gilstate_runtime_state {

Include/internal/pycore_runtime_init.h

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ extern "C" {
4141
.header = 1, \
4242
}, \
4343
}, \
44+
.ceval = { \
45+
.perf = _PyEval_RUNTIME_PERF_INIT, \
46+
}, \
4447
.gilstate = { \
4548
.check_enabled = 1, \
4649
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \

Makefile.pre.in

+1
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ PYTHON_HEADERS= \
16231623
$(srcdir)/Include/internal/pycore_bytesobject.h \
16241624
$(srcdir)/Include/internal/pycore_call.h \
16251625
$(srcdir)/Include/internal/pycore_ceval.h \
1626+
$(srcdir)/Include/internal/pycore_ceval_state.h \
16261627
$(srcdir)/Include/internal/pycore_code.h \
16271628
$(srcdir)/Include/internal/pycore_compile.h \
16281629
$(srcdir)/Include/internal/pycore_condvar.h \

PCbuild/pythoncore.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@
204204
<ClInclude Include="..\Include\internal\pycore_bytesobject.h" />
205205
<ClInclude Include="..\Include\internal\pycore_call.h" />
206206
<ClInclude Include="..\Include\internal\pycore_ceval.h" />
207+
<ClInclude Include="..\Include\internal\pycore_ceval_state.h" />
207208
<ClInclude Include="..\Include\internal\pycore_code.h" />
208209
<ClInclude Include="..\Include\internal\pycore_compile.h" />
209210
<ClInclude Include="..\Include\internal\pycore_condvar.h" />

PCbuild/pythoncore.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,9 @@
519519
<ClInclude Include="..\Include\internal\pycore_ceval.h">
520520
<Filter>Include\internal</Filter>
521521
</ClInclude>
522+
<ClInclude Include="..\Include\internal\pycore_ceval_state.h">
523+
<Filter>Include\internal</Filter>
524+
</ClInclude>
522525
<ClInclude Include="..\Include\internal\pycore_code.h">
523526
<Filter>Include\internal</Filter>
524527
</ClInclude>

Python/perf_trampoline.c

+14-30
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,6 @@ any DWARF information available for them).
134134
#include "pycore_frame.h"
135135
#include "pycore_interp.h"
136136

137-
typedef enum {
138-
PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state
139-
PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized
140-
PERF_STATUS_OK = 1, // Perf trampoline is ready to be executed
141-
} perf_status_t;
142137

143138
#ifdef PY_HAVE_PERF_TRAMPOLINE
144139

@@ -190,24 +185,13 @@ struct code_arena_st {
190185
};
191186

192187
typedef struct code_arena_st code_arena_t;
193-
194-
struct trampoline_api_st {
195-
void* (*init_state)(void);
196-
void (*write_state)(void* state, const void *code_addr,
197-
unsigned int code_size, PyCodeObject* code);
198-
int (*free_state)(void* state);
199-
void *state;
200-
};
201-
202188
typedef struct trampoline_api_st trampoline_api_t;
203189

204-
205-
static perf_status_t perf_status = PERF_STATUS_NO_INIT;
206-
static Py_ssize_t extra_code_index = -1;
207-
static code_arena_t *code_arena;
208-
static trampoline_api_t trampoline_api;
209-
210-
static FILE *perf_map_file;
190+
#define perf_status _PyRuntime.ceval.perf.status
191+
#define extra_code_index _PyRuntime.ceval.perf.extra_code_index
192+
#define perf_code_arena _PyRuntime.ceval.perf.code_arena
193+
#define trampoline_api _PyRuntime.ceval.perf.trampoline_api
194+
#define perf_map_file _PyRuntime.ceval.perf.map_file
211195

212196
static void *
213197
perf_map_get_file(void)
@@ -344,17 +328,17 @@ new_code_arena(void)
344328
new_arena->size = mem_size;
345329
new_arena->size_left = mem_size;
346330
new_arena->code_size = code_size;
347-
new_arena->prev = code_arena;
348-
code_arena = new_arena;
331+
new_arena->prev = perf_code_arena;
332+
perf_code_arena = new_arena;
349333
return 0;
350334
}
351335

352336
static void
353337
free_code_arenas(void)
354338
{
355-
code_arena_t *cur = code_arena;
339+
code_arena_t *cur = perf_code_arena;
356340
code_arena_t *prev;
357-
code_arena = NULL; // invalid static pointer
341+
perf_code_arena = NULL; // invalid static pointer
358342
while (cur) {
359343
munmap(cur->start_addr, cur->size);
360344
prev = cur->prev;
@@ -375,14 +359,14 @@ code_arena_new_code(code_arena_t *code_arena)
375359
static inline py_trampoline
376360
compile_trampoline(void)
377361
{
378-
if ((code_arena == NULL) ||
379-
(code_arena->size_left <= code_arena->code_size)) {
362+
if ((perf_code_arena == NULL) ||
363+
(perf_code_arena->size_left <= perf_code_arena->code_size)) {
380364
if (new_code_arena() < 0) {
381365
return NULL;
382366
}
383367
}
384-
assert(code_arena->size_left <= code_arena->size);
385-
return code_arena_new_code(code_arena);
368+
assert(perf_code_arena->size_left <= perf_code_arena->size);
369+
return code_arena_new_code(perf_code_arena);
386370
}
387371

388372
static PyObject *
@@ -405,7 +389,7 @@ py_trampoline_evaluator(PyThreadState *ts, _PyInterpreterFrame *frame,
405389
goto default_eval;
406390
}
407391
trampoline_api.write_state(trampoline_api.state, new_trampoline,
408-
code_arena->code_size, co);
392+
perf_code_arena->code_size, co);
409393
_PyCode_SetExtra((PyObject *)co, extra_code_index,
410394
(void *)new_trampoline);
411395
f = new_trampoline;

Tools/c-analyzer/cpython/globals-to-fix.tsv

+1-13
Original file line numberDiff line numberDiff line change
@@ -302,21 +302,10 @@ Objects/sliceobject.c - _Py_EllipsisObject -
302302
##################################
303303
## global non-objects to fix in core code
304304

305-
##-----------------------
306-
## effectively-const but initialized lazily
307-
308-
## others
309-
Python/perf_trampoline.c - perf_map_file -
310-
311305
##-----------------------
312306
## state
313307

314-
## other
315308
Objects/object.c - _Py_RefTotal -
316-
Python/perf_trampoline.c - perf_status -
317-
Python/perf_trampoline.c - extra_code_index -
318-
Python/perf_trampoline.c - code_arena -
319-
Python/perf_trampoline.c - trampoline_api -
320309
Python/thread_pthread_stubs.h - py_tls_entries -
321310

322311

@@ -374,9 +363,8 @@ Modules/itertoolsmodule.c - teedataobject_type -
374363
Modules/itertoolsmodule.c - ziplongest_type -
375364

376365
##-----------------------
377-
## other
378-
379366
## state
367+
380368
Modules/faulthandler.c - fatal_error -
381369
Modules/faulthandler.c - thread -
382370
Modules/faulthandler.c - user_signals -

0 commit comments

Comments
 (0)