mirror of https://github.com/python/cpython
bpo-45522: Allow to disable freelists on build time (GH-29056)
Freelists for object structs can now be disabled. A new ``configure`` option ``--without-freelists`` can be used to disable all freelists except empty tuple singleton. Internal Py*_MAXFREELIST macros can now be defined as 0 without causing compiler warnings and segfaults. Signed-off-by: Christian Heimes <christian@python.org>
This commit is contained in:
parent
5a14f71fe8
commit
9942f42a93
|
@ -481,6 +481,11 @@ Build Changes
|
||||||
``isinf()``, ``isnan()``, ``round()``.
|
``isinf()``, ``isnan()``, ``round()``.
|
||||||
(Contributed by Victor Stinner in :issue:`45440`.)
|
(Contributed by Victor Stinner in :issue:`45440`.)
|
||||||
|
|
||||||
|
* Freelists for object structs can now be disabled. A new :program:`configure`
|
||||||
|
option :option:`!--without-freelists` can be used to disable all freelists
|
||||||
|
except empty tuple singleton.
|
||||||
|
(Contributed by Christian Heimes in :issue:`45522`)
|
||||||
|
|
||||||
C API Changes
|
C API Changes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -85,12 +85,31 @@ struct _Py_unicode_state {
|
||||||
struct _Py_unicode_ids ids;
|
struct _Py_unicode_ids ids;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef WITH_FREELISTS
|
||||||
|
// without freelists
|
||||||
|
# define PyFloat_MAXFREELIST 0
|
||||||
|
// for tuples only store empty tuple singleton
|
||||||
|
# define PyTuple_MAXSAVESIZE 1
|
||||||
|
# define PyTuple_MAXFREELIST 1
|
||||||
|
# define PyList_MAXFREELIST 0
|
||||||
|
# define PyDict_MAXFREELIST 0
|
||||||
|
# define PyFrame_MAXFREELIST 0
|
||||||
|
# define _PyAsyncGen_MAXFREELIST 0
|
||||||
|
# define PyContext_MAXFREELIST 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PyFloat_MAXFREELIST
|
||||||
|
# define PyFloat_MAXFREELIST 100
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _Py_float_state {
|
struct _Py_float_state {
|
||||||
|
#if PyFloat_MAXFREELIST > 0
|
||||||
/* Special free list
|
/* Special free list
|
||||||
free_list is a singly-linked list of available PyFloatObjects,
|
free_list is a singly-linked list of available PyFloatObjects,
|
||||||
linked via abuse of their ob_type members. */
|
linked via abuse of their ob_type members. */
|
||||||
int numfree;
|
int numfree;
|
||||||
PyFloatObject *free_list;
|
PyFloatObject *free_list;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Speed optimization to avoid frequent malloc/free of small tuples */
|
/* Speed optimization to avoid frequent malloc/free of small tuples */
|
||||||
|
@ -119,8 +138,10 @@ struct _Py_tuple_state {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct _Py_list_state {
|
struct _Py_list_state {
|
||||||
|
#if PyList_MAXFREELIST > 0
|
||||||
PyListObject *free_list[PyList_MAXFREELIST];
|
PyListObject *free_list[PyList_MAXFREELIST];
|
||||||
int numfree;
|
int numfree;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef PyDict_MAXFREELIST
|
#ifndef PyDict_MAXFREELIST
|
||||||
|
@ -128,17 +149,25 @@ struct _Py_list_state {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct _Py_dict_state {
|
struct _Py_dict_state {
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
/* Dictionary reuse scheme to save calls to malloc and free */
|
/* Dictionary reuse scheme to save calls to malloc and free */
|
||||||
PyDictObject *free_list[PyDict_MAXFREELIST];
|
PyDictObject *free_list[PyDict_MAXFREELIST];
|
||||||
int numfree;
|
int numfree;
|
||||||
PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
|
PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
|
||||||
int keys_numfree;
|
int keys_numfree;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef PyFrame_MAXFREELIST
|
||||||
|
# define PyFrame_MAXFREELIST 200
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _Py_frame_state {
|
struct _Py_frame_state {
|
||||||
|
#if PyFrame_MAXFREELIST > 0
|
||||||
PyFrameObject *free_list;
|
PyFrameObject *free_list;
|
||||||
/* number of frames currently in free_list */
|
/* number of frames currently in free_list */
|
||||||
int numfree;
|
int numfree;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef _PyAsyncGen_MAXFREELIST
|
#ifndef _PyAsyncGen_MAXFREELIST
|
||||||
|
@ -146,6 +175,7 @@ struct _Py_frame_state {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct _Py_async_gen_state {
|
struct _Py_async_gen_state {
|
||||||
|
#if _PyAsyncGen_MAXFREELIST > 0
|
||||||
/* Freelists boost performance 6-10%; they also reduce memory
|
/* Freelists boost performance 6-10%; they also reduce memory
|
||||||
fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend
|
fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend
|
||||||
are short-living objects that are instantiated for every
|
are short-living objects that are instantiated for every
|
||||||
|
@ -155,12 +185,19 @@ struct _Py_async_gen_state {
|
||||||
|
|
||||||
struct PyAsyncGenASend* asend_freelist[_PyAsyncGen_MAXFREELIST];
|
struct PyAsyncGenASend* asend_freelist[_PyAsyncGen_MAXFREELIST];
|
||||||
int asend_numfree;
|
int asend_numfree;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef PyContext_MAXFREELIST
|
||||||
|
# define PyContext_MAXFREELIST 255
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _Py_context_state {
|
struct _Py_context_state {
|
||||||
|
#if PyContext_MAXFREELIST > 0
|
||||||
// List of free PyContext objects
|
// List of free PyContext objects
|
||||||
PyContext *freelist;
|
PyContext *freelist;
|
||||||
int numfree;
|
int numfree;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _Py_exc_state {
|
struct _Py_exc_state {
|
||||||
|
|
|
@ -825,7 +825,18 @@ class SysModuleTest(unittest.TestCase):
|
||||||
from test.support.script_helper import assert_python_ok
|
from test.support.script_helper import assert_python_ok
|
||||||
args = ['-c', 'import sys; sys._debugmallocstats()']
|
args = ['-c', 'import sys; sys._debugmallocstats()']
|
||||||
ret, out, err = assert_python_ok(*args)
|
ret, out, err = assert_python_ok(*args)
|
||||||
self.assertIn(b"free PyDictObjects", err)
|
|
||||||
|
# Output of sys._debugmallocstats() depends on configure flags.
|
||||||
|
# The sysconfig vars are not available on Windows.
|
||||||
|
if sys.platform != "win32":
|
||||||
|
with_freelists = sysconfig.get_config_var("WITH_FREELISTS")
|
||||||
|
with_pymalloc = sysconfig.get_config_var("WITH_PYMALLOC")
|
||||||
|
if with_freelists:
|
||||||
|
self.assertIn(b"free PyDictObjects", err)
|
||||||
|
if with_pymalloc:
|
||||||
|
self.assertIn(b'Small block threshold', err)
|
||||||
|
if not with_freelists and not with_pymalloc:
|
||||||
|
self.assertFalse(err)
|
||||||
|
|
||||||
# The function has no parameter
|
# The function has no parameter
|
||||||
self.assertRaises(TypeError, sys._debugmallocstats, True)
|
self.assertRaises(TypeError, sys._debugmallocstats, True)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
The internal freelists for frame, float, list, dict, async generators, and
|
||||||
|
context objects can now be disabled.
|
|
@ -240,17 +240,20 @@ uint64_t _pydict_global_version = 0;
|
||||||
#include "clinic/dictobject.c.h"
|
#include "clinic/dictobject.c.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
static struct _Py_dict_state *
|
static struct _Py_dict_state *
|
||||||
get_dict_state(void)
|
get_dict_state(void)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
return &interp->dict_state;
|
return &interp->dict_state;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyDict_ClearFreeList(PyInterpreterState *interp)
|
_PyDict_ClearFreeList(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = &interp->dict_state;
|
struct _Py_dict_state *state = &interp->dict_state;
|
||||||
while (state->numfree) {
|
while (state->numfree) {
|
||||||
PyDictObject *op = state->free_list[--state->numfree];
|
PyDictObject *op = state->free_list[--state->numfree];
|
||||||
|
@ -260,6 +263,7 @@ _PyDict_ClearFreeList(PyInterpreterState *interp)
|
||||||
while (state->keys_numfree) {
|
while (state->keys_numfree) {
|
||||||
PyObject_Free(state->keys_free_list[--state->keys_numfree]);
|
PyObject_Free(state->keys_free_list[--state->keys_numfree]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,7 +271,7 @@ void
|
||||||
_PyDict_Fini(PyInterpreterState *interp)
|
_PyDict_Fini(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyDict_ClearFreeList(interp);
|
_PyDict_ClearFreeList(interp);
|
||||||
#ifdef Py_DEBUG
|
#if defined(Py_DEBUG) && PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = &interp->dict_state;
|
struct _Py_dict_state *state = &interp->dict_state;
|
||||||
state->numfree = -1;
|
state->numfree = -1;
|
||||||
state->keys_numfree = -1;
|
state->keys_numfree = -1;
|
||||||
|
@ -279,9 +283,11 @@ _PyDict_Fini(PyInterpreterState *interp)
|
||||||
void
|
void
|
||||||
_PyDict_DebugMallocStats(FILE *out)
|
_PyDict_DebugMallocStats(FILE *out)
|
||||||
{
|
{
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = get_dict_state();
|
struct _Py_dict_state *state = get_dict_state();
|
||||||
_PyDebugAllocatorStats(out, "free PyDictObject",
|
_PyDebugAllocatorStats(out, "free PyDictObject",
|
||||||
state->numfree, sizeof(PyDictObject));
|
state->numfree, sizeof(PyDictObject));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DK_MASK(dk) (DK_SIZE(dk)-1)
|
#define DK_MASK(dk) (DK_SIZE(dk)-1)
|
||||||
|
@ -570,6 +576,7 @@ new_keys_object(uint8_t log2_size)
|
||||||
es = sizeof(Py_ssize_t);
|
es = sizeof(Py_ssize_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = get_dict_state();
|
struct _Py_dict_state *state = get_dict_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// new_keys_object() must not be called after _PyDict_Fini()
|
// new_keys_object() must not be called after _PyDict_Fini()
|
||||||
|
@ -579,6 +586,7 @@ new_keys_object(uint8_t log2_size)
|
||||||
dk = state->keys_free_list[--state->keys_numfree];
|
dk = state->keys_free_list[--state->keys_numfree];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
dk = PyObject_Malloc(sizeof(PyDictKeysObject)
|
dk = PyObject_Malloc(sizeof(PyDictKeysObject)
|
||||||
+ (es<<log2_size)
|
+ (es<<log2_size)
|
||||||
|
@ -611,6 +619,7 @@ free_keys_object(PyDictKeysObject *keys)
|
||||||
Py_XDECREF(entries[i].me_key);
|
Py_XDECREF(entries[i].me_key);
|
||||||
Py_XDECREF(entries[i].me_value);
|
Py_XDECREF(entries[i].me_value);
|
||||||
}
|
}
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = get_dict_state();
|
struct _Py_dict_state *state = get_dict_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// free_keys_object() must not be called after _PyDict_Fini()
|
// free_keys_object() must not be called after _PyDict_Fini()
|
||||||
|
@ -620,6 +629,7 @@ free_keys_object(PyDictKeysObject *keys)
|
||||||
state->keys_free_list[state->keys_numfree++] = keys;
|
state->keys_free_list[state->keys_numfree++] = keys;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
PyObject_Free(keys);
|
PyObject_Free(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,6 +648,7 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free
|
||||||
{
|
{
|
||||||
PyDictObject *mp;
|
PyDictObject *mp;
|
||||||
assert(keys != NULL);
|
assert(keys != NULL);
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = get_dict_state();
|
struct _Py_dict_state *state = get_dict_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// new_dict() must not be called after _PyDict_Fini()
|
// new_dict() must not be called after _PyDict_Fini()
|
||||||
|
@ -649,7 +660,9 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free
|
||||||
assert (Py_IS_TYPE(mp, &PyDict_Type));
|
assert (Py_IS_TYPE(mp, &PyDict_Type));
|
||||||
_Py_NewReference((PyObject *)mp);
|
_Py_NewReference((PyObject *)mp);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
|
mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
|
||||||
if (mp == NULL) {
|
if (mp == NULL) {
|
||||||
dictkeys_decref(keys);
|
dictkeys_decref(keys);
|
||||||
|
@ -1259,6 +1272,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize)
|
||||||
#ifdef Py_REF_DEBUG
|
#ifdef Py_REF_DEBUG
|
||||||
_Py_RefTotal--;
|
_Py_RefTotal--;
|
||||||
#endif
|
#endif
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = get_dict_state();
|
struct _Py_dict_state *state = get_dict_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// dictresize() must not be called after _PyDict_Fini()
|
// dictresize() must not be called after _PyDict_Fini()
|
||||||
|
@ -1269,7 +1283,9 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize)
|
||||||
{
|
{
|
||||||
state->keys_free_list[state->keys_numfree++] = oldkeys;
|
state->keys_free_list[state->keys_numfree++] = oldkeys;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
PyObject_Free(oldkeys);
|
PyObject_Free(oldkeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1987,6 +2003,7 @@ dict_dealloc(PyDictObject *mp)
|
||||||
assert(keys->dk_refcnt == 1);
|
assert(keys->dk_refcnt == 1);
|
||||||
dictkeys_decref(keys);
|
dictkeys_decref(keys);
|
||||||
}
|
}
|
||||||
|
#if PyDict_MAXFREELIST > 0
|
||||||
struct _Py_dict_state *state = get_dict_state();
|
struct _Py_dict_state *state = get_dict_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// new_dict() must not be called after _PyDict_Fini()
|
// new_dict() must not be called after _PyDict_Fini()
|
||||||
|
@ -1995,7 +2012,9 @@ dict_dealloc(PyDictObject *mp)
|
||||||
if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
|
if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
|
||||||
state->free_list[state->numfree++] = mp;
|
state->free_list[state->numfree++] = mp;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
Py_TYPE(mp)->tp_free((PyObject *)mp);
|
Py_TYPE(mp)->tp_free((PyObject *)mp);
|
||||||
}
|
}
|
||||||
Py_TRASHCAN_END
|
Py_TRASHCAN_END
|
||||||
|
|
|
@ -28,12 +28,14 @@ class float "PyObject *" "&PyFloat_Type"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if PyFloat_MAXFREELIST > 0
|
||||||
static struct _Py_float_state *
|
static struct _Py_float_state *
|
||||||
get_float_state(void)
|
get_float_state(void)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
return &interp->float_state;
|
return &interp->float_state;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
double
|
double
|
||||||
|
@ -126,8 +128,10 @@ PyFloat_GetInfo(void)
|
||||||
PyObject *
|
PyObject *
|
||||||
PyFloat_FromDouble(double fval)
|
PyFloat_FromDouble(double fval)
|
||||||
{
|
{
|
||||||
|
PyFloatObject *op;
|
||||||
|
#if PyFloat_MAXFREELIST > 0
|
||||||
struct _Py_float_state *state = get_float_state();
|
struct _Py_float_state *state = get_float_state();
|
||||||
PyFloatObject *op = state->free_list;
|
op = state->free_list;
|
||||||
if (op != NULL) {
|
if (op != NULL) {
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// PyFloat_FromDouble() must not be called after _PyFloat_Fini()
|
// PyFloat_FromDouble() must not be called after _PyFloat_Fini()
|
||||||
|
@ -136,7 +140,9 @@ PyFloat_FromDouble(double fval)
|
||||||
state->free_list = (PyFloatObject *) Py_TYPE(op);
|
state->free_list = (PyFloatObject *) Py_TYPE(op);
|
||||||
state->numfree--;
|
state->numfree--;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
op = PyObject_Malloc(sizeof(PyFloatObject));
|
op = PyObject_Malloc(sizeof(PyFloatObject));
|
||||||
if (!op) {
|
if (!op) {
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
@ -233,6 +239,7 @@ PyFloat_FromString(PyObject *v)
|
||||||
static void
|
static void
|
||||||
float_dealloc(PyFloatObject *op)
|
float_dealloc(PyFloatObject *op)
|
||||||
{
|
{
|
||||||
|
#if PyFloat_MAXFREELIST > 0
|
||||||
if (PyFloat_CheckExact(op)) {
|
if (PyFloat_CheckExact(op)) {
|
||||||
struct _Py_float_state *state = get_float_state();
|
struct _Py_float_state *state = get_float_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
|
@ -247,7 +254,9 @@ float_dealloc(PyFloatObject *op)
|
||||||
Py_SET_TYPE(op, (PyTypeObject *)state->free_list);
|
Py_SET_TYPE(op, (PyTypeObject *)state->free_list);
|
||||||
state->free_list = op;
|
state->free_list = op;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
Py_TYPE(op)->tp_free((PyObject *)op);
|
Py_TYPE(op)->tp_free((PyObject *)op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2036,6 +2045,7 @@ _PyFloat_InitTypes(void)
|
||||||
void
|
void
|
||||||
_PyFloat_ClearFreeList(PyInterpreterState *interp)
|
_PyFloat_ClearFreeList(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
#if PyFloat_MAXFREELIST > 0
|
||||||
struct _Py_float_state *state = &interp->float_state;
|
struct _Py_float_state *state = &interp->float_state;
|
||||||
PyFloatObject *f = state->free_list;
|
PyFloatObject *f = state->free_list;
|
||||||
while (f != NULL) {
|
while (f != NULL) {
|
||||||
|
@ -2045,13 +2055,14 @@ _PyFloat_ClearFreeList(PyInterpreterState *interp)
|
||||||
}
|
}
|
||||||
state->free_list = NULL;
|
state->free_list = NULL;
|
||||||
state->numfree = 0;
|
state->numfree = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyFloat_Fini(PyInterpreterState *interp)
|
_PyFloat_Fini(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyFloat_ClearFreeList(interp);
|
_PyFloat_ClearFreeList(interp);
|
||||||
#ifdef Py_DEBUG
|
#if defined(Py_DEBUG) && PyFloat_MAXFREELIST > 0
|
||||||
struct _Py_float_state *state = &interp->float_state;
|
struct _Py_float_state *state = &interp->float_state;
|
||||||
state->numfree = -1;
|
state->numfree = -1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2061,10 +2072,12 @@ _PyFloat_Fini(PyInterpreterState *interp)
|
||||||
void
|
void
|
||||||
_PyFloat_DebugMallocStats(FILE *out)
|
_PyFloat_DebugMallocStats(FILE *out)
|
||||||
{
|
{
|
||||||
|
#if PyFloat_MAXFREELIST > 0
|
||||||
struct _Py_float_state *state = get_float_state();
|
struct _Py_float_state *state = get_float_state();
|
||||||
_PyDebugAllocatorStats(out,
|
_PyDebugAllocatorStats(out,
|
||||||
"free PyFloatObject",
|
"free PyFloatObject",
|
||||||
state->numfree, sizeof(PyFloatObject));
|
state->numfree, sizeof(PyFloatObject));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,14 @@ static PyMemberDef frame_memberlist[] = {
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if PyFrame_MAXFREELIST > 0
|
||||||
static struct _Py_frame_state *
|
static struct _Py_frame_state *
|
||||||
get_frame_state(void)
|
get_frame_state(void)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
return &interp->frame;
|
return &interp->frame;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -607,9 +609,6 @@ static PyGetSetDef frame_getsetlist[] = {
|
||||||
f_back next item on free list, or NULL
|
f_back next item on free list, or NULL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* max value for numfree */
|
|
||||||
#define PyFrame_MAXFREELIST 200
|
|
||||||
|
|
||||||
static void _Py_HOT_FUNCTION
|
static void _Py_HOT_FUNCTION
|
||||||
frame_dealloc(PyFrameObject *f)
|
frame_dealloc(PyFrameObject *f)
|
||||||
{
|
{
|
||||||
|
@ -638,6 +637,7 @@ frame_dealloc(PyFrameObject *f)
|
||||||
}
|
}
|
||||||
Py_CLEAR(f->f_back);
|
Py_CLEAR(f->f_back);
|
||||||
Py_CLEAR(f->f_trace);
|
Py_CLEAR(f->f_trace);
|
||||||
|
#if PyFrame_MAXFREELIST > 0
|
||||||
struct _Py_frame_state *state = get_frame_state();
|
struct _Py_frame_state *state = get_frame_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// frame_dealloc() must not be called after _PyFrame_Fini()
|
// frame_dealloc() must not be called after _PyFrame_Fini()
|
||||||
|
@ -648,7 +648,9 @@ frame_dealloc(PyFrameObject *f)
|
||||||
f->f_back = state->free_list;
|
f->f_back = state->free_list;
|
||||||
state->free_list = f;
|
state->free_list = f;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
PyObject_GC_Del(f);
|
PyObject_GC_Del(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,8 +803,10 @@ static inline PyFrameObject*
|
||||||
frame_alloc(InterpreterFrame *frame, int owns)
|
frame_alloc(InterpreterFrame *frame, int owns)
|
||||||
{
|
{
|
||||||
PyFrameObject *f;
|
PyFrameObject *f;
|
||||||
|
#if PyFrame_MAXFREELIST > 0
|
||||||
struct _Py_frame_state *state = get_frame_state();
|
struct _Py_frame_state *state = get_frame_state();
|
||||||
if (state->free_list == NULL)
|
if (state->free_list == NULL)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
f = PyObject_GC_New(PyFrameObject, &PyFrame_Type);
|
f = PyObject_GC_New(PyFrameObject, &PyFrame_Type);
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
|
@ -816,7 +820,9 @@ frame_alloc(InterpreterFrame *frame, int owns)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
#if PyFrame_MAXFREELIST > 0
|
||||||
|
else
|
||||||
|
{
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// frame_alloc() must not be called after _PyFrame_Fini()
|
// frame_alloc() must not be called after _PyFrame_Fini()
|
||||||
assert(state->numfree != -1);
|
assert(state->numfree != -1);
|
||||||
|
@ -827,6 +833,7 @@ frame_alloc(InterpreterFrame *frame, int owns)
|
||||||
state->free_list = state->free_list->f_back;
|
state->free_list = state->free_list->f_back;
|
||||||
_Py_NewReference((PyObject *)f);
|
_Py_NewReference((PyObject *)f);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
f->f_frame = frame;
|
f->f_frame = frame;
|
||||||
f->f_own_locals_memory = owns;
|
f->f_own_locals_memory = owns;
|
||||||
return f;
|
return f;
|
||||||
|
@ -1069,6 +1076,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
||||||
void
|
void
|
||||||
_PyFrame_ClearFreeList(PyInterpreterState *interp)
|
_PyFrame_ClearFreeList(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
#if PyFrame_MAXFREELIST > 0
|
||||||
struct _Py_frame_state *state = &interp->frame;
|
struct _Py_frame_state *state = &interp->frame;
|
||||||
while (state->free_list != NULL) {
|
while (state->free_list != NULL) {
|
||||||
PyFrameObject *f = state->free_list;
|
PyFrameObject *f = state->free_list;
|
||||||
|
@ -1077,13 +1085,14 @@ _PyFrame_ClearFreeList(PyInterpreterState *interp)
|
||||||
--state->numfree;
|
--state->numfree;
|
||||||
}
|
}
|
||||||
assert(state->numfree == 0);
|
assert(state->numfree == 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyFrame_Fini(PyInterpreterState *interp)
|
_PyFrame_Fini(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyFrame_ClearFreeList(interp);
|
_PyFrame_ClearFreeList(interp);
|
||||||
#ifdef Py_DEBUG
|
#if defined(Py_DEBUG) && PyFrame_MAXFREELIST > 0
|
||||||
struct _Py_frame_state *state = &interp->frame;
|
struct _Py_frame_state *state = &interp->frame;
|
||||||
state->numfree = -1;
|
state->numfree = -1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1093,10 +1102,12 @@ _PyFrame_Fini(PyInterpreterState *interp)
|
||||||
void
|
void
|
||||||
_PyFrame_DebugMallocStats(FILE *out)
|
_PyFrame_DebugMallocStats(FILE *out)
|
||||||
{
|
{
|
||||||
|
#if PyFrame_MAXFREELIST > 0
|
||||||
struct _Py_frame_state *state = get_frame_state();
|
struct _Py_frame_state *state = get_frame_state();
|
||||||
_PyDebugAllocatorStats(out,
|
_PyDebugAllocatorStats(out,
|
||||||
"free PyFrameObject",
|
"free PyFrameObject",
|
||||||
state->numfree, sizeof(PyFrameObject));
|
state->numfree, sizeof(PyFrameObject));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1567,12 +1567,14 @@ PyTypeObject PyAsyncGen_Type = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if _PyAsyncGen_MAXFREELIST > 0
|
||||||
static struct _Py_async_gen_state *
|
static struct _Py_async_gen_state *
|
||||||
get_async_gen_state(void)
|
get_async_gen_state(void)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
return &interp->async_gen;
|
return &interp->async_gen;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -1595,6 +1597,7 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname)
|
||||||
void
|
void
|
||||||
_PyAsyncGen_ClearFreeLists(PyInterpreterState *interp)
|
_PyAsyncGen_ClearFreeLists(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
#if _PyAsyncGen_MAXFREELIST > 0
|
||||||
struct _Py_async_gen_state *state = &interp->async_gen;
|
struct _Py_async_gen_state *state = &interp->async_gen;
|
||||||
|
|
||||||
while (state->value_numfree) {
|
while (state->value_numfree) {
|
||||||
|
@ -1610,13 +1613,14 @@ _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp)
|
||||||
assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type));
|
assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type));
|
||||||
PyObject_GC_Del(o);
|
PyObject_GC_Del(o);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyAsyncGen_Fini(PyInterpreterState *interp)
|
_PyAsyncGen_Fini(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyAsyncGen_ClearFreeLists(interp);
|
_PyAsyncGen_ClearFreeLists(interp);
|
||||||
#ifdef Py_DEBUG
|
#if defined(Py_DEBUG) && _PyAsyncGen_MAXFREELIST > 0
|
||||||
struct _Py_async_gen_state *state = &interp->async_gen;
|
struct _Py_async_gen_state *state = &interp->async_gen;
|
||||||
state->value_numfree = -1;
|
state->value_numfree = -1;
|
||||||
state->asend_numfree = -1;
|
state->asend_numfree = -1;
|
||||||
|
@ -1663,6 +1667,7 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
|
||||||
_PyObject_GC_UNTRACK((PyObject *)o);
|
_PyObject_GC_UNTRACK((PyObject *)o);
|
||||||
Py_CLEAR(o->ags_gen);
|
Py_CLEAR(o->ags_gen);
|
||||||
Py_CLEAR(o->ags_sendval);
|
Py_CLEAR(o->ags_sendval);
|
||||||
|
#if _PyAsyncGen_MAXFREELIST > 0
|
||||||
struct _Py_async_gen_state *state = get_async_gen_state();
|
struct _Py_async_gen_state *state = get_async_gen_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini()
|
// async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini()
|
||||||
|
@ -1672,7 +1677,9 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
|
||||||
assert(PyAsyncGenASend_CheckExact(o));
|
assert(PyAsyncGenASend_CheckExact(o));
|
||||||
state->asend_freelist[state->asend_numfree++] = o;
|
state->asend_freelist[state->asend_numfree++] = o;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
PyObject_GC_Del(o);
|
PyObject_GC_Del(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1825,6 +1832,7 @@ static PyObject *
|
||||||
async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
|
async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
|
||||||
{
|
{
|
||||||
PyAsyncGenASend *o;
|
PyAsyncGenASend *o;
|
||||||
|
#if _PyAsyncGen_MAXFREELIST > 0
|
||||||
struct _Py_async_gen_state *state = get_async_gen_state();
|
struct _Py_async_gen_state *state = get_async_gen_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// async_gen_asend_new() must not be called after _PyAsyncGen_Fini()
|
// async_gen_asend_new() must not be called after _PyAsyncGen_Fini()
|
||||||
|
@ -1835,7 +1843,9 @@ async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
|
||||||
o = state->asend_freelist[state->asend_numfree];
|
o = state->asend_freelist[state->asend_numfree];
|
||||||
_Py_NewReference((PyObject *)o);
|
_Py_NewReference((PyObject *)o);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type);
|
o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type);
|
||||||
if (o == NULL) {
|
if (o == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1863,6 +1873,7 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o)
|
||||||
{
|
{
|
||||||
_PyObject_GC_UNTRACK((PyObject *)o);
|
_PyObject_GC_UNTRACK((PyObject *)o);
|
||||||
Py_CLEAR(o->agw_val);
|
Py_CLEAR(o->agw_val);
|
||||||
|
#if _PyAsyncGen_MAXFREELIST > 0
|
||||||
struct _Py_async_gen_state *state = get_async_gen_state();
|
struct _Py_async_gen_state *state = get_async_gen_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini()
|
// async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini()
|
||||||
|
@ -1872,7 +1883,9 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o)
|
||||||
assert(_PyAsyncGenWrappedValue_CheckExact(o));
|
assert(_PyAsyncGenWrappedValue_CheckExact(o));
|
||||||
state->value_freelist[state->value_numfree++] = o;
|
state->value_freelist[state->value_numfree++] = o;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
PyObject_GC_Del(o);
|
PyObject_GC_Del(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1936,6 +1949,7 @@ _PyAsyncGenValueWrapperNew(PyObject *val)
|
||||||
_PyAsyncGenWrappedValue *o;
|
_PyAsyncGenWrappedValue *o;
|
||||||
assert(val);
|
assert(val);
|
||||||
|
|
||||||
|
#if _PyAsyncGen_MAXFREELIST > 0
|
||||||
struct _Py_async_gen_state *state = get_async_gen_state();
|
struct _Py_async_gen_state *state = get_async_gen_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini()
|
// _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini()
|
||||||
|
@ -1947,7 +1961,9 @@ _PyAsyncGenValueWrapperNew(PyObject *val)
|
||||||
assert(_PyAsyncGenWrappedValue_CheckExact(o));
|
assert(_PyAsyncGenWrappedValue_CheckExact(o));
|
||||||
_Py_NewReference((PyObject*)o);
|
_Py_NewReference((PyObject*)o);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
o = PyObject_GC_New(_PyAsyncGenWrappedValue,
|
o = PyObject_GC_New(_PyAsyncGenWrappedValue,
|
||||||
&_PyAsyncGenWrappedValue_Type);
|
&_PyAsyncGenWrappedValue_Type);
|
||||||
if (o == NULL) {
|
if (o == NULL) {
|
||||||
|
|
|
@ -19,13 +19,14 @@ class list "PyListObject *" "&PyList_Type"
|
||||||
|
|
||||||
#include "clinic/listobject.c.h"
|
#include "clinic/listobject.c.h"
|
||||||
|
|
||||||
|
#if PyList_MAXFREELIST > 0
|
||||||
static struct _Py_list_state *
|
static struct _Py_list_state *
|
||||||
get_list_state(void)
|
get_list_state(void)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
return &interp->list;
|
return &interp->list;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Ensure ob_item has room for at least newsize elements, and set
|
/* Ensure ob_item has room for at least newsize elements, and set
|
||||||
|
@ -108,19 +109,21 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
|
||||||
void
|
void
|
||||||
_PyList_ClearFreeList(PyInterpreterState *interp)
|
_PyList_ClearFreeList(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
#if PyList_MAXFREELIST > 0
|
||||||
struct _Py_list_state *state = &interp->list;
|
struct _Py_list_state *state = &interp->list;
|
||||||
while (state->numfree) {
|
while (state->numfree) {
|
||||||
PyListObject *op = state->free_list[--state->numfree];
|
PyListObject *op = state->free_list[--state->numfree];
|
||||||
assert(PyList_CheckExact(op));
|
assert(PyList_CheckExact(op));
|
||||||
PyObject_GC_Del(op);
|
PyObject_GC_Del(op);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyList_Fini(PyInterpreterState *interp)
|
_PyList_Fini(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyList_ClearFreeList(interp);
|
_PyList_ClearFreeList(interp);
|
||||||
#ifdef Py_DEBUG
|
#if defined(Py_DEBUG) && PyList_MAXFREELIST > 0
|
||||||
struct _Py_list_state *state = &interp->list;
|
struct _Py_list_state *state = &interp->list;
|
||||||
state->numfree = -1;
|
state->numfree = -1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -130,32 +133,38 @@ _PyList_Fini(PyInterpreterState *interp)
|
||||||
void
|
void
|
||||||
_PyList_DebugMallocStats(FILE *out)
|
_PyList_DebugMallocStats(FILE *out)
|
||||||
{
|
{
|
||||||
|
#if PyList_MAXFREELIST > 0
|
||||||
struct _Py_list_state *state = get_list_state();
|
struct _Py_list_state *state = get_list_state();
|
||||||
_PyDebugAllocatorStats(out,
|
_PyDebugAllocatorStats(out,
|
||||||
"free PyListObject",
|
"free PyListObject",
|
||||||
state->numfree, sizeof(PyListObject));
|
state->numfree, sizeof(PyListObject));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyList_New(Py_ssize_t size)
|
PyList_New(Py_ssize_t size)
|
||||||
{
|
{
|
||||||
|
PyListObject *op;
|
||||||
|
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PyList_MAXFREELIST > 0
|
||||||
struct _Py_list_state *state = get_list_state();
|
struct _Py_list_state *state = get_list_state();
|
||||||
PyListObject *op;
|
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// PyList_New() must not be called after _PyList_Fini()
|
// PyList_New() must not be called after _PyList_Fini()
|
||||||
assert(state->numfree != -1);
|
assert(state->numfree != -1);
|
||||||
#endif
|
#endif
|
||||||
if (state->numfree) {
|
if (PyList_MAXFREELIST && state->numfree) {
|
||||||
state->numfree--;
|
state->numfree--;
|
||||||
op = state->free_list[state->numfree];
|
op = state->free_list[state->numfree];
|
||||||
_Py_NewReference((PyObject *)op);
|
_Py_NewReference((PyObject *)op);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
op = PyObject_GC_New(PyListObject, &PyList_Type);
|
op = PyObject_GC_New(PyListObject, &PyList_Type);
|
||||||
if (op == NULL) {
|
if (op == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -344,6 +353,7 @@ list_dealloc(PyListObject *op)
|
||||||
}
|
}
|
||||||
PyMem_Free(op->ob_item);
|
PyMem_Free(op->ob_item);
|
||||||
}
|
}
|
||||||
|
#if PyList_MAXFREELIST > 0
|
||||||
struct _Py_list_state *state = get_list_state();
|
struct _Py_list_state *state = get_list_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// list_dealloc() must not be called after _PyList_Fini()
|
// list_dealloc() must not be called after _PyList_Fini()
|
||||||
|
@ -352,7 +362,9 @@ list_dealloc(PyListObject *op)
|
||||||
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
|
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
|
||||||
state->free_list[state->numfree++] = op;
|
state->free_list[state->numfree++] = op;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
Py_TYPE(op)->tp_free((PyObject *)op);
|
Py_TYPE(op)->tp_free((PyObject *)op);
|
||||||
}
|
}
|
||||||
Py_TRASHCAN_END
|
Py_TRASHCAN_END
|
||||||
|
|
|
@ -66,7 +66,8 @@ tuple_alloc(Py_ssize_t size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PyTuple_MAXSAVESIZE > 0
|
// Check for max save size > 1. Empty tuple singleton is special case.
|
||||||
|
#if PyTuple_MAXSAVESIZE > 1
|
||||||
struct _Py_tuple_state *state = get_tuple_state();
|
struct _Py_tuple_state *state = get_tuple_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// tuple_alloc() must not be called after _PyTuple_Fini()
|
// tuple_alloc() must not be called after _PyTuple_Fini()
|
||||||
|
|
|
@ -463,6 +463,9 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
|
||||||
/* Use Python's own small-block memory-allocator. */
|
/* Use Python's own small-block memory-allocator. */
|
||||||
#define WITH_PYMALLOC 1
|
#define WITH_PYMALLOC 1
|
||||||
|
|
||||||
|
/* Define if you want to compile in object freelists optimization */
|
||||||
|
#define WITH_FREELISTS 1
|
||||||
|
|
||||||
/* Define if you have clock. */
|
/* Define if you have clock. */
|
||||||
/* #define HAVE_CLOCK */
|
/* #define HAVE_CLOCK */
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
#include "structmember.h" // PyMemberDef
|
#include "structmember.h" // PyMemberDef
|
||||||
|
|
||||||
|
|
||||||
#define CONTEXT_FREELIST_MAXLEN 255
|
|
||||||
|
|
||||||
|
|
||||||
#include "clinic/context.c.h"
|
#include "clinic/context.c.h"
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
module _contextvars
|
module _contextvars
|
||||||
|
@ -66,12 +63,14 @@ static int
|
||||||
contextvar_del(PyContextVar *var);
|
contextvar_del(PyContextVar *var);
|
||||||
|
|
||||||
|
|
||||||
|
#if PyContext_MAXFREELIST > 0
|
||||||
static struct _Py_context_state *
|
static struct _Py_context_state *
|
||||||
get_context_state(void)
|
get_context_state(void)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
return &interp->context;
|
return &interp->context;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -340,8 +339,9 @@ class _contextvars.Context "PyContext *" "&PyContext_Type"
|
||||||
static inline PyContext *
|
static inline PyContext *
|
||||||
_context_alloc(void)
|
_context_alloc(void)
|
||||||
{
|
{
|
||||||
struct _Py_context_state *state = get_context_state();
|
|
||||||
PyContext *ctx;
|
PyContext *ctx;
|
||||||
|
#if PyContext_MAXFREELIST > 0
|
||||||
|
struct _Py_context_state *state = get_context_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// _context_alloc() must not be called after _PyContext_Fini()
|
// _context_alloc() must not be called after _PyContext_Fini()
|
||||||
assert(state->numfree != -1);
|
assert(state->numfree != -1);
|
||||||
|
@ -353,7 +353,9 @@ _context_alloc(void)
|
||||||
ctx->ctx_weakreflist = NULL;
|
ctx->ctx_weakreflist = NULL;
|
||||||
_Py_NewReference((PyObject *)ctx);
|
_Py_NewReference((PyObject *)ctx);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
ctx = PyObject_GC_New(PyContext, &PyContext_Type);
|
ctx = PyObject_GC_New(PyContext, &PyContext_Type);
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -469,17 +471,20 @@ context_tp_dealloc(PyContext *self)
|
||||||
}
|
}
|
||||||
(void)context_tp_clear(self);
|
(void)context_tp_clear(self);
|
||||||
|
|
||||||
|
#if PyContext_MAXFREELIST > 0
|
||||||
struct _Py_context_state *state = get_context_state();
|
struct _Py_context_state *state = get_context_state();
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// _context_alloc() must not be called after _PyContext_Fini()
|
// _context_alloc() must not be called after _PyContext_Fini()
|
||||||
assert(state->numfree != -1);
|
assert(state->numfree != -1);
|
||||||
#endif
|
#endif
|
||||||
if (state->numfree < CONTEXT_FREELIST_MAXLEN) {
|
if (state->numfree < PyContext_MAXFREELIST) {
|
||||||
state->numfree++;
|
state->numfree++;
|
||||||
self->ctx_weakreflist = (PyObject *)state->freelist;
|
self->ctx_weakreflist = (PyObject *)state->freelist;
|
||||||
state->freelist = self;
|
state->freelist = self;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
Py_TYPE(self)->tp_free(self);
|
Py_TYPE(self)->tp_free(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1289,6 +1294,7 @@ get_token_missing(void)
|
||||||
void
|
void
|
||||||
_PyContext_ClearFreeList(PyInterpreterState *interp)
|
_PyContext_ClearFreeList(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
#if PyContext_MAXFREELIST > 0
|
||||||
struct _Py_context_state *state = &interp->context;
|
struct _Py_context_state *state = &interp->context;
|
||||||
for (; state->numfree; state->numfree--) {
|
for (; state->numfree; state->numfree--) {
|
||||||
PyContext *ctx = state->freelist;
|
PyContext *ctx = state->freelist;
|
||||||
|
@ -1296,6 +1302,7 @@ _PyContext_ClearFreeList(PyInterpreterState *interp)
|
||||||
ctx->ctx_weakreflist = NULL;
|
ctx->ctx_weakreflist = NULL;
|
||||||
PyObject_GC_Del(ctx);
|
PyObject_GC_Del(ctx);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1306,7 +1313,7 @@ _PyContext_Fini(PyInterpreterState *interp)
|
||||||
Py_CLEAR(_token_missing);
|
Py_CLEAR(_token_missing);
|
||||||
}
|
}
|
||||||
_PyContext_ClearFreeList(interp);
|
_PyContext_ClearFreeList(interp);
|
||||||
#ifdef Py_DEBUG
|
#if defined(Py_DEBUG) && PyContext_MAXFREELIST > 0
|
||||||
struct _Py_context_state *state = &interp->context;
|
struct _Py_context_state *state = &interp->context;
|
||||||
state->numfree = -1;
|
state->numfree = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -846,6 +846,7 @@ with_dbmliborder
|
||||||
enable_ipv6
|
enable_ipv6
|
||||||
with_doc_strings
|
with_doc_strings
|
||||||
with_pymalloc
|
with_pymalloc
|
||||||
|
with_freelists
|
||||||
with_c_locale_coercion
|
with_c_locale_coercion
|
||||||
with_valgrind
|
with_valgrind
|
||||||
with_dtrace
|
with_dtrace
|
||||||
|
@ -1588,6 +1589,7 @@ Optional Packages:
|
||||||
names `ndbm', `gdbm' and `bdb'.
|
names `ndbm', `gdbm' and `bdb'.
|
||||||
--with-doc-strings enable documentation strings (default is yes)
|
--with-doc-strings enable documentation strings (default is yes)
|
||||||
--with-pymalloc enable specialized mallocs (default is yes)
|
--with-pymalloc enable specialized mallocs (default is yes)
|
||||||
|
--with-freelists enable object freelists (default is yes)
|
||||||
--with-c-locale-coercion
|
--with-c-locale-coercion
|
||||||
enable C locale coercion to a UTF-8 based locale
|
enable C locale coercion to a UTF-8 based locale
|
||||||
(default is yes)
|
(default is yes)
|
||||||
|
@ -11728,6 +11730,30 @@ fi
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_pymalloc" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_pymalloc" >&5
|
||||||
$as_echo "$with_pymalloc" >&6; }
|
$as_echo "$with_pymalloc" >&6; }
|
||||||
|
|
||||||
|
# Check whether objects such as float, tuple and dict are using
|
||||||
|
# freelists to optimization memory allocation.
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-freelists" >&5
|
||||||
|
$as_echo_n "checking for --with-freelists... " >&6; }
|
||||||
|
|
||||||
|
# Check whether --with-freelists was given.
|
||||||
|
if test "${with_freelists+set}" = set; then :
|
||||||
|
withval=$with_freelists;
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if test -z "$with_freelists"
|
||||||
|
then
|
||||||
|
with_freelists="yes"
|
||||||
|
fi
|
||||||
|
if test "$with_freelists" != "no"
|
||||||
|
then
|
||||||
|
|
||||||
|
$as_echo "#define WITH_FREELISTS 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_freelists" >&5
|
||||||
|
$as_echo "$with_freelists" >&6; }
|
||||||
|
|
||||||
# Check for --with-c-locale-coercion
|
# Check for --with-c-locale-coercion
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-c-locale-coercion" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-c-locale-coercion" >&5
|
||||||
$as_echo_n "checking for --with-c-locale-coercion... " >&6; }
|
$as_echo_n "checking for --with-c-locale-coercion... " >&6; }
|
||||||
|
|
17
configure.ac
17
configure.ac
|
@ -3616,6 +3616,23 @@ then
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT($with_pymalloc)
|
AC_MSG_RESULT($with_pymalloc)
|
||||||
|
|
||||||
|
# Check whether objects such as float, tuple and dict are using
|
||||||
|
# freelists to optimization memory allocation.
|
||||||
|
AC_MSG_CHECKING(for --with-freelists)
|
||||||
|
AC_ARG_WITH(freelists,
|
||||||
|
AS_HELP_STRING([--with-freelists], [enable object freelists (default is yes)]))
|
||||||
|
|
||||||
|
if test -z "$with_freelists"
|
||||||
|
then
|
||||||
|
with_freelists="yes"
|
||||||
|
fi
|
||||||
|
if test "$with_freelists" != "no"
|
||||||
|
then
|
||||||
|
AC_DEFINE(WITH_FREELISTS, 1,
|
||||||
|
[Define if you want to compile in object freelists optimization])
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT($with_freelists)
|
||||||
|
|
||||||
# Check for --with-c-locale-coercion
|
# Check for --with-c-locale-coercion
|
||||||
AC_MSG_CHECKING(for --with-c-locale-coercion)
|
AC_MSG_CHECKING(for --with-c-locale-coercion)
|
||||||
AC_ARG_WITH(c-locale-coercion,
|
AC_ARG_WITH(c-locale-coercion,
|
||||||
|
|
|
@ -1555,6 +1555,9 @@
|
||||||
/* Define to build the readline module against Editline. */
|
/* Define to build the readline module against Editline. */
|
||||||
#undef WITH_EDITLINE
|
#undef WITH_EDITLINE
|
||||||
|
|
||||||
|
/* Define if you want to compile in object freelists optimization */
|
||||||
|
#undef WITH_FREELISTS
|
||||||
|
|
||||||
/* Define to 1 if libintl is needed for locale functions. */
|
/* Define to 1 if libintl is needed for locale functions. */
|
||||||
#undef WITH_LIBINTL
|
#undef WITH_LIBINTL
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue