[Python-checkins] bpo-40137: Move state lookups out of the critical path (GH-25492)

rhettinger webhook-mailer at python.org
Wed Apr 21 18:22:30 EDT 2021


https://github.com/python/cpython/commit/139c232f3851b393798d0ea4e65f1298bfbcd9cf
commit: 139c232f3851b393798d0ea4e65f1298bfbcd9cf
branch: master
author: Raymond Hettinger <rhettinger at users.noreply.github.com>
committer: rhettinger <rhettinger at users.noreply.github.com>
date: 2021-04-21T15:22:22-07:00
summary:

bpo-40137: Move state lookups out of the critical path (GH-25492)

files:
M Modules/_functoolsmodule.c

diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 1fcaf299e67bc6..f3ae3b62ae332c 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -12,18 +12,6 @@
    All rights reserved.
 */
 
-/* partial object **********************************************************/
-
-typedef struct {
-    PyObject_HEAD
-    PyObject *fn;
-    PyObject *args;
-    PyObject *kw;
-    PyObject *dict;        /* __dict__ */
-    PyObject *weakreflist; /* List of weak references */
-    vectorcallfunc vectorcall;
-} partialobject;
-
 typedef struct _functools_state {
     /* this object is used delimit args and keywords in the cache keys */
     PyObject *kwd_mark;
@@ -40,6 +28,19 @@ get_functools_state(PyObject *module)
     return (_functools_state *)state;
 }
 
+
+/* partial object **********************************************************/
+
+typedef struct {
+    PyObject_HEAD
+    PyObject *fn;
+    PyObject *args;
+    PyObject *kw;
+    PyObject *dict;        /* __dict__ */
+    PyObject *weakreflist; /* List of weak references */
+    vectorcallfunc vectorcall;
+} partialobject;
+
 static void partial_setvectorcall(partialobject *pto);
 static struct PyModuleDef _functools_module;
 static PyObject *
@@ -781,13 +782,16 @@ typedef struct lru_cache_object {
     PyObject *func;
     Py_ssize_t maxsize;
     Py_ssize_t misses;
+    /* the kwd_mark is used delimit args and keywords in the cache keys */
+    PyObject *kwd_mark;
+    PyTypeObject *lru_list_elem_type;
     PyObject *cache_info_type;
     PyObject *dict;
     PyObject *weakreflist;
 } lru_cache_object;
 
 static PyObject *
-lru_cache_make_key(_functools_state *state, PyObject *args,
+lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
                    PyObject *kwds, int typed)
 {
     PyObject *key, *keyword, *value;
@@ -827,8 +831,8 @@ lru_cache_make_key(_functools_state *state, PyObject *args,
         PyTuple_SET_ITEM(key, key_pos++, item);
     }
     if (kwds_size) {
-        Py_INCREF(state->kwd_mark);
-        PyTuple_SET_ITEM(key, key_pos++, state->kwd_mark);
+        Py_INCREF(kwd_mark);
+        PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
         for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
             Py_INCREF(keyword);
             PyTuple_SET_ITEM(key, key_pos++, keyword);
@@ -872,12 +876,7 @@ infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
 {
     PyObject *result;
     Py_hash_t hash;
-    _functools_state *state;
-    state = get_functools_state_by_type(Py_TYPE(self));
-    if (state == NULL) {
-        return NULL;
-    }
-    PyObject *key = lru_cache_make_key(state, args, kwds, self->typed);
+    PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
     if (!key)
         return NULL;
     hash = PyObject_Hash(key);
@@ -977,13 +976,8 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
     lru_list_elem *link;
     PyObject *key, *result, *testresult;
     Py_hash_t hash;
-    _functools_state *state;
 
-    state = get_functools_state_by_type(Py_TYPE(self));
-    if (state == NULL) {
-        return NULL;
-    }
-    key = lru_cache_make_key(state, args, kwds, self->typed);
+    key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
     if (!key)
         return NULL;
     hash = PyObject_Hash(key);
@@ -1038,7 +1032,7 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
     {
         /* Cache is not full, so put the result in a new link */
         link = (lru_list_elem *)PyObject_New(lru_list_elem,
-                                             state->lru_list_elem_type);
+                                             self->lru_list_elem_type);
         if (link == NULL) {
             Py_DECREF(key);
             Py_DECREF(result);
@@ -1149,6 +1143,7 @@ lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
     lru_cache_object *obj;
     Py_ssize_t maxsize;
     PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
+    _functools_state *state;
     static char *keywords[] = {"user_function", "maxsize", "typed",
                                "cache_info_type", NULL};
 
@@ -1164,6 +1159,11 @@ lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
         return NULL;
     }
 
+    state = get_functools_state_by_type(type);
+    if (state == NULL) {
+        return NULL;
+    }
+
     /* select the caching function, and make/inc maxsize_O */
     if (maxsize_O == Py_None) {
         wrapper = infinite_lru_cache_wrapper;
@@ -1203,6 +1203,10 @@ lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
     obj->func = func;
     obj->misses = obj->hits = 0;
     obj->maxsize = maxsize;
+    Py_INCREF(state->kwd_mark);
+    obj->kwd_mark = state->kwd_mark;
+    Py_INCREF(state->lru_list_elem_type);
+    obj->lru_list_elem_type = state->lru_list_elem_type;
     Py_INCREF(cache_info_type);
     obj->cache_info_type = cache_info_type;
     obj->dict = NULL;
@@ -1238,6 +1242,8 @@ lru_cache_tp_clear(lru_cache_object *self)
     lru_list_elem *list = lru_cache_unlink_list(self);
     Py_CLEAR(self->func);
     Py_CLEAR(self->cache);
+    Py_CLEAR(self->kwd_mark);
+    Py_CLEAR(self->lru_list_elem_type);
     Py_CLEAR(self->cache_info_type);
     Py_CLEAR(self->dict);
     lru_cache_clear_list(list);
@@ -1330,6 +1336,8 @@ lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
     }
     Py_VISIT(self->func);
     Py_VISIT(self->cache);
+    Py_VISIT(self->kwd_mark);
+    Py_VISIT(self->lru_list_elem_type);
     Py_VISIT(self->cache_info_type);
     Py_VISIT(self->dict);
     return 0;



More information about the Python-checkins mailing list