summaryrefslogtreecommitdiffstats
path: root/Include/internal
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-06-04 21:38:36 (GMT)
committerGitHub <noreply@github.com>2020-06-04 21:38:36 (GMT)
commit69ac6e58fd98de339c013fe64cd1cf763e4f9bca (patch)
tree98ab5b8f851d5512f097a73292e871a89c11f873 /Include/internal
parentdc24b8a2ac32114313bae519db3ccc21fe45c982 (diff)
downloadcpython-69ac6e58fd98de339c013fe64cd1cf763e4f9bca.zip
cpython-69ac6e58fd98de339c013fe64cd1cf763e4f9bca.tar.gz
cpython-69ac6e58fd98de339c013fe64cd1cf763e4f9bca.tar.bz2
bpo-40521: Make tuple free list per-interpreter (GH-20247)
Each interpreter now has its own tuple free lists: * Move tuple numfree and free_list arrays into PyInterpreterState. * Define PyTuple_MAXSAVESIZE and PyTuple_MAXFREELIST macros in pycore_interp.h. * Add _Py_tuple_state structure. Pass it explicitly to tuple_alloc(). * Add tstate parameter to _PyTuple_ClearFreeList() * Each interpreter now has its own empty tuple singleton.
Diffstat (limited to 'Include/internal')
-rw-r--r--Include/internal/pycore_gc.h2
-rw-r--r--Include/internal/pycore_interp.h21
-rw-r--r--Include/internal/pycore_pylifecycle.h2
3 files changed, 23 insertions, 2 deletions
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h
index 0511eea..e8e5d32 100644
--- a/Include/internal/pycore_gc.h
+++ b/Include/internal/pycore_gc.h
@@ -166,7 +166,7 @@ PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
// Functions to clear types free lists
extern void _PyFrame_ClearFreeList(void);
-extern void _PyTuple_ClearFreeList(void);
+extern void _PyTuple_ClearFreeList(PyThreadState *tstate);
extern void _PyFloat_ClearFreeList(void);
extern void _PyList_ClearFreeList(void);
extern void _PyDict_ClearFreeList(void);
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index f04ea33..b90bfbe 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -64,6 +64,26 @@ struct _Py_unicode_state {
struct _Py_unicode_fs_codec fs_codec;
};
+/* Speed optimization to avoid frequent malloc/free of small tuples */
+#ifndef PyTuple_MAXSAVESIZE
+ // Largest tuple to save on free list
+# define PyTuple_MAXSAVESIZE 20
+#endif
+#ifndef PyTuple_MAXFREELIST
+ // Maximum number of tuples of each size to save
+# define PyTuple_MAXFREELIST 2000
+#endif
+
+struct _Py_tuple_state {
+#if PyTuple_MAXSAVESIZE > 0
+ /* Entries 1 up to PyTuple_MAXSAVESIZE are free lists,
+ entry 0 is the empty tuple () of which at most one instance
+ will be allocated. */
+ PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
+ int numfree[PyTuple_MAXSAVESIZE];
+#endif
+};
+
/* interpreter state */
@@ -157,6 +177,7 @@ struct _is {
*/
PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS];
#endif
+ struct _Py_tuple_state tuple;
};
/* Used by _PyImport_Cleanup() */
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index 77ea3f2..3f2ff5b 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -60,7 +60,7 @@ extern PyStatus _PyGC_Init(PyThreadState *tstate);
extern void _PyFrame_Fini(void);
extern void _PyDict_Fini(void);
-extern void _PyTuple_Fini(void);
+extern void _PyTuple_Fini(PyThreadState *tstate);
extern void _PyList_Fini(void);
extern void _PySet_Fini(void);
extern void _PyBytes_Fini(void);