gh-100227: Move the dtoa State to PyInterpreterState (gh-102331)

https://github.com/python/cpython/issues/100227
This commit is contained in:
Eric Snow 2023-02-28 13:14:40 -07:00 committed by GitHub
parent b5ff382433
commit f300a1fa4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 17 deletions

View file

@ -24,10 +24,11 @@ Bigint {
#ifdef Py_USING_MEMORY_DEBUGGER #ifdef Py_USING_MEMORY_DEBUGGER
struct _dtoa_runtime_state { struct _dtoa_state {
int _not_used; int _not_used;
}; };
#define _dtoa_runtime_state_INIT {0} #define _dtoa_interp_state_INIT(INTERP) \
{0}
#else // !Py_USING_MEMORY_DEBUGGER #else // !Py_USING_MEMORY_DEBUGGER
@ -40,7 +41,7 @@ struct _dtoa_runtime_state {
#define Bigint_PREALLOC_SIZE \ #define Bigint_PREALLOC_SIZE \
((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
struct _dtoa_runtime_state { struct _dtoa_state {
/* p5s is a linked list of powers of 5 of the form 5**(2**i), i >= 2 */ /* p5s is a linked list of powers of 5 of the form 5**(2**i), i >= 2 */
// XXX This should be freed during runtime fini. // XXX This should be freed during runtime fini.
struct Bigint *p5s; struct Bigint *p5s;
@ -48,9 +49,9 @@ struct _dtoa_runtime_state {
double preallocated[Bigint_PREALLOC_SIZE]; double preallocated[Bigint_PREALLOC_SIZE];
double *preallocated_next; double *preallocated_next;
}; };
#define _dtoa_runtime_state_INIT(runtime) \ #define _dtoa_state_INIT(INTERP) \
{ \ { \
.preallocated_next = runtime.dtoa.preallocated, \ .preallocated_next = (INTERP)->dtoa.preallocated, \
} }
#endif // !Py_USING_MEMORY_DEBUGGER #endif // !Py_USING_MEMORY_DEBUGGER

View file

@ -16,6 +16,7 @@ extern "C" {
#include "pycore_code.h" // struct callable_cache #include "pycore_code.h" // struct callable_cache
#include "pycore_context.h" // struct _Py_context_state #include "pycore_context.h" // struct _Py_context_state
#include "pycore_dict_state.h" // struct _Py_dict_state #include "pycore_dict_state.h" // struct _Py_dict_state
#include "pycore_dtoa.h" // struct _dtoa_state
#include "pycore_exceptions.h" // struct _Py_exc_state #include "pycore_exceptions.h" // struct _Py_exc_state
#include "pycore_floatobject.h" // struct _Py_float_state #include "pycore_floatobject.h" // struct _Py_float_state
#include "pycore_function.h" // FUNC_MAX_WATCHERS #include "pycore_function.h" // FUNC_MAX_WATCHERS
@ -139,6 +140,7 @@ struct _is {
struct _Py_unicode_state unicode; struct _Py_unicode_state unicode;
struct _Py_float_state float_state; struct _Py_float_state float_state;
struct _Py_long_state long_state; struct _Py_long_state long_state;
struct _dtoa_state dtoa;
/* Using a cache is very effective since typically only a single slice is /* Using a cache is very effective since typically only a single slice is
created and then deleted again. */ created and then deleted again. */
PySliceObject *slice_cache; PySliceObject *slice_cache;

View file

@ -11,7 +11,6 @@ extern "C" {
#include "pycore_atomic.h" /* _Py_atomic_address */ #include "pycore_atomic.h" /* _Py_atomic_address */
#include "pycore_ceval_state.h" // struct _ceval_runtime_state #include "pycore_ceval_state.h" // struct _ceval_runtime_state
#include "pycore_dict_state.h" // struct _Py_dict_runtime_state #include "pycore_dict_state.h" // struct _Py_dict_runtime_state
#include "pycore_dtoa.h" // struct _dtoa_runtime_state
#include "pycore_floatobject.h" // struct _Py_float_runtime_state #include "pycore_floatobject.h" // struct _Py_float_runtime_state
#include "pycore_faulthandler.h" // struct _faulthandler_runtime_state #include "pycore_faulthandler.h" // struct _faulthandler_runtime_state
#include "pycore_function.h" // struct _func_runtime_state #include "pycore_function.h" // struct _func_runtime_state
@ -141,7 +140,6 @@ typedef struct pyruntimestate {
struct _ceval_runtime_state ceval; struct _ceval_runtime_state ceval;
struct _gilstate_runtime_state gilstate; struct _gilstate_runtime_state gilstate;
struct _getargs_runtime_state getargs; struct _getargs_runtime_state getargs;
struct _dtoa_runtime_state dtoa;
struct _fileutils_state fileutils; struct _fileutils_state fileutils;
struct _faulthandler_runtime_state faulthandler; struct _faulthandler_runtime_state faulthandler;
struct _tracemalloc_runtime_state tracemalloc; struct _tracemalloc_runtime_state tracemalloc;

View file

@ -53,7 +53,6 @@ extern "C" {
.gilstate = { \ .gilstate = { \
.check_enabled = 1, \ .check_enabled = 1, \
}, \ }, \
.dtoa = _dtoa_runtime_state_INIT(runtime), \
.fileutils = { \ .fileutils = { \
.force_ascii = -1, \ .force_ascii = -1, \
}, \ }, \
@ -94,10 +93,10 @@ extern "C" {
}, \ }, \
}, \ }, \
}, \ }, \
._main_interpreter = _PyInterpreterState_INIT, \ ._main_interpreter = _PyInterpreterState_INIT(runtime._main_interpreter), \
} }
#define _PyInterpreterState_INIT \ #define _PyInterpreterState_INIT(INTERP) \
{ \ { \
.id_refcount = -1, \ .id_refcount = -1, \
.imports = IMPORTS_INIT, \ .imports = IMPORTS_INIT, \
@ -113,6 +112,7 @@ extern "C" {
{ .threshold = 10, }, \ { .threshold = 10, }, \
}, \ }, \
}, \ }, \
.dtoa = _dtoa_state_INIT(&(INTERP)), \
.static_objects = { \ .static_objects = { \
.singletons = { \ .singletons = { \
._not_used = 1, \ ._not_used = 1, \

View file

@ -119,7 +119,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_dtoa.h" // _PY_SHORT_FLOAT_REPR #include "pycore_dtoa.h" // _PY_SHORT_FLOAT_REPR
#include "pycore_runtime.h" // _PyRuntime #include "pycore_pystate.h" // _PyInterpreterState_GET()
#include <stdlib.h> // exit() #include <stdlib.h> // exit()
/* if _PY_SHORT_FLOAT_REPR == 0, then don't even try to compile /* if _PY_SHORT_FLOAT_REPR == 0, then don't even try to compile
@ -339,9 +339,9 @@ typedef struct Bigint Bigint;
Bfree to PyMem_Free. Investigate whether this has any significant Bfree to PyMem_Free. Investigate whether this has any significant
performance on impact. */ performance on impact. */
#define freelist _PyRuntime.dtoa.freelist #define freelist interp->dtoa.freelist
#define private_mem _PyRuntime.dtoa.preallocated #define private_mem interp->dtoa.preallocated
#define pmem_next _PyRuntime.dtoa.preallocated_next #define pmem_next interp->dtoa.preallocated_next
/* Allocate space for a Bigint with up to 1<<k digits */ /* Allocate space for a Bigint with up to 1<<k digits */
@ -351,6 +351,7 @@ Balloc(int k)
int x; int x;
Bigint *rv; Bigint *rv;
unsigned int len; unsigned int len;
PyInterpreterState *interp = _PyInterpreterState_GET();
if (k <= Bigint_Kmax && (rv = freelist[k])) if (k <= Bigint_Kmax && (rv = freelist[k]))
freelist[k] = rv->next; freelist[k] = rv->next;
@ -385,6 +386,7 @@ Bfree(Bigint *v)
if (v->k > Bigint_Kmax) if (v->k > Bigint_Kmax)
FREE((void*)v); FREE((void*)v);
else { else {
PyInterpreterState *interp = _PyInterpreterState_GET();
v->next = freelist[v->k]; v->next = freelist[v->k];
freelist[v->k] = v; freelist[v->k] = v;
} }
@ -692,7 +694,8 @@ pow5mult(Bigint *b, int k)
if (!(k >>= 2)) if (!(k >>= 2))
return b; return b;
p5 = _PyRuntime.dtoa.p5s; PyInterpreterState *interp = _PyInterpreterState_GET();
p5 = interp->dtoa.p5s;
if (!p5) { if (!p5) {
/* first time */ /* first time */
p5 = i2b(625); p5 = i2b(625);
@ -700,7 +703,7 @@ pow5mult(Bigint *b, int k)
Bfree(b); Bfree(b);
return NULL; return NULL;
} }
_PyRuntime.dtoa.p5s = p5; interp->dtoa.p5s = p5;
p5->next = 0; p5->next = 0;
} }
for(;;) { for(;;) {

View file

@ -4,6 +4,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_ceval.h" #include "pycore_ceval.h"
#include "pycore_code.h" // stats #include "pycore_code.h" // stats
#include "pycore_dtoa.h" // _dtoa_state_INIT()
#include "pycore_frame.h" #include "pycore_frame.h"
#include "pycore_initconfig.h" #include "pycore_initconfig.h"
#include "pycore_object.h" // _PyType_InitCache() #include "pycore_object.h" // _PyType_InitCache()
@ -618,6 +619,18 @@ free_interpreter(PyInterpreterState *interp)
e.g. by PyMem_RawCalloc() or memset(), or otherwise pre-initialized. e.g. by PyMem_RawCalloc() or memset(), or otherwise pre-initialized.
The runtime state is not manipulated. Instead it is assumed that The runtime state is not manipulated. Instead it is assumed that
the interpreter is getting added to the runtime. the interpreter is getting added to the runtime.
Note that the main interpreter was statically initialized as part
of the runtime and most state is already set properly. That leaves
a small number of fields to initialize dynamically, as well as some
that are initialized lazily.
For subinterpreters we memcpy() the main interpreter in
PyInterpreterState_New(), leaving it in the same mostly-initialized
state. The only difference is that the interpreter has some
self-referential state that is statically initializexd to the
main interpreter. We fix those fields here, in addition
to the other dynamically initialized fields.
*/ */
static void static void
@ -645,6 +658,11 @@ init_interpreter(PyInterpreterState *interp,
PyConfig_InitPythonConfig(&interp->config); PyConfig_InitPythonConfig(&interp->config);
_PyType_InitCache(interp); _PyType_InitCache(interp);
if (interp != &runtime->_main_interpreter) {
/* Fix the self-referential, statically initialized fields. */
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
}
interp->_initialized = 1; interp->_initialized = 1;
} }