diff options
author | Raymond Hettinger <rhettinger@users.noreply.github.com> | 2021-04-21 22:22:22 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-21 22:22:22 (GMT) |
commit | 139c232f3851b393798d0ea4e65f1298bfbcd9cf (patch) | |
tree | c6a893db153d6650aa3f84ac4095033aad866d26 /Modules/_functoolsmodule.c | |
parent | 760da626ff4124e1344fd8b7dbeb83b2c4b7c12c (diff) | |
download | cpython-139c232f3851b393798d0ea4e65f1298bfbcd9cf.zip cpython-139c232f3851b393798d0ea4e65f1298bfbcd9cf.tar.gz cpython-139c232f3851b393798d0ea4e65f1298bfbcd9cf.tar.bz2 |
bpo-40137: Move state lookups out of the critical path (GH-25492)
Diffstat (limited to 'Modules/_functoolsmodule.c')
-rw-r--r-- | Modules/_functoolsmodule.c | 64 |
1 files changed, 36 insertions, 28 deletions
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 1fcaf29..f3ae3b6 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; |