Skip to content

Commit 139c232

Browse files
authored
bpo-40137: Move state lookups out of the critical path (pythonGH-25492)
1 parent 760da62 commit 139c232

File tree

1 file changed

+36
-28
lines changed

1 file changed

+36
-28
lines changed

Modules/_functoolsmodule.c

+36-28
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,6 @@
1212
All rights reserved.
1313
*/
1414

15-
/* partial object **********************************************************/
16-
17-
typedef struct {
18-
PyObject_HEAD
19-
PyObject *fn;
20-
PyObject *args;
21-
PyObject *kw;
22-
PyObject *dict; /* __dict__ */
23-
PyObject *weakreflist; /* List of weak references */
24-
vectorcallfunc vectorcall;
25-
} partialobject;
26-
2715
typedef struct _functools_state {
2816
/* this object is used delimit args and keywords in the cache keys */
2917
PyObject *kwd_mark;
@@ -40,6 +28,19 @@ get_functools_state(PyObject *module)
4028
return (_functools_state *)state;
4129
}
4230

31+
32+
/* partial object **********************************************************/
33+
34+
typedef struct {
35+
PyObject_HEAD
36+
PyObject *fn;
37+
PyObject *args;
38+
PyObject *kw;
39+
PyObject *dict; /* __dict__ */
40+
PyObject *weakreflist; /* List of weak references */
41+
vectorcallfunc vectorcall;
42+
} partialobject;
43+
4344
static void partial_setvectorcall(partialobject *pto);
4445
static struct PyModuleDef _functools_module;
4546
static PyObject *
@@ -781,13 +782,16 @@ typedef struct lru_cache_object {
781782
PyObject *func;
782783
Py_ssize_t maxsize;
783784
Py_ssize_t misses;
785+
/* the kwd_mark is used delimit args and keywords in the cache keys */
786+
PyObject *kwd_mark;
787+
PyTypeObject *lru_list_elem_type;
784788
PyObject *cache_info_type;
785789
PyObject *dict;
786790
PyObject *weakreflist;
787791
} lru_cache_object;
788792

789793
static PyObject *
790-
lru_cache_make_key(_functools_state *state, PyObject *args,
794+
lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
791795
PyObject *kwds, int typed)
792796
{
793797
PyObject *key, *keyword, *value;
@@ -827,8 +831,8 @@ lru_cache_make_key(_functools_state *state, PyObject *args,
827831
PyTuple_SET_ITEM(key, key_pos++, item);
828832
}
829833
if (kwds_size) {
830-
Py_INCREF(state->kwd_mark);
831-
PyTuple_SET_ITEM(key, key_pos++, state->kwd_mark);
834+
Py_INCREF(kwd_mark);
835+
PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
832836
for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
833837
Py_INCREF(keyword);
834838
PyTuple_SET_ITEM(key, key_pos++, keyword);
@@ -872,12 +876,7 @@ infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
872876
{
873877
PyObject *result;
874878
Py_hash_t hash;
875-
_functools_state *state;
876-
state = get_functools_state_by_type(Py_TYPE(self));
877-
if (state == NULL) {
878-
return NULL;
879-
}
880-
PyObject *key = lru_cache_make_key(state, args, kwds, self->typed);
879+
PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
881880
if (!key)
882881
return NULL;
883882
hash = PyObject_Hash(key);
@@ -977,13 +976,8 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
977976
lru_list_elem *link;
978977
PyObject *key, *result, *testresult;
979978
Py_hash_t hash;
980-
_functools_state *state;
981979

982-
state = get_functools_state_by_type(Py_TYPE(self));
983-
if (state == NULL) {
984-
return NULL;
985-
}
986-
key = lru_cache_make_key(state, args, kwds, self->typed);
980+
key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
987981
if (!key)
988982
return NULL;
989983
hash = PyObject_Hash(key);
@@ -1038,7 +1032,7 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
10381032
{
10391033
/* Cache is not full, so put the result in a new link */
10401034
link = (lru_list_elem *)PyObject_New(lru_list_elem,
1041-
state->lru_list_elem_type);
1035+
self->lru_list_elem_type);
10421036
if (link == NULL) {
10431037
Py_DECREF(key);
10441038
Py_DECREF(result);
@@ -1149,6 +1143,7 @@ lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
11491143
lru_cache_object *obj;
11501144
Py_ssize_t maxsize;
11511145
PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
1146+
_functools_state *state;
11521147
static char *keywords[] = {"user_function", "maxsize", "typed",
11531148
"cache_info_type", NULL};
11541149

@@ -1164,6 +1159,11 @@ lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
11641159
return NULL;
11651160
}
11661161

1162+
state = get_functools_state_by_type(type);
1163+
if (state == NULL) {
1164+
return NULL;
1165+
}
1166+
11671167
/* select the caching function, and make/inc maxsize_O */
11681168
if (maxsize_O == Py_None) {
11691169
wrapper = infinite_lru_cache_wrapper;
@@ -1203,6 +1203,10 @@ lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
12031203
obj->func = func;
12041204
obj->misses = obj->hits = 0;
12051205
obj->maxsize = maxsize;
1206+
Py_INCREF(state->kwd_mark);
1207+
obj->kwd_mark = state->kwd_mark;
1208+
Py_INCREF(state->lru_list_elem_type);
1209+
obj->lru_list_elem_type = state->lru_list_elem_type;
12061210
Py_INCREF(cache_info_type);
12071211
obj->cache_info_type = cache_info_type;
12081212
obj->dict = NULL;
@@ -1238,6 +1242,8 @@ lru_cache_tp_clear(lru_cache_object *self)
12381242
lru_list_elem *list = lru_cache_unlink_list(self);
12391243
Py_CLEAR(self->func);
12401244
Py_CLEAR(self->cache);
1245+
Py_CLEAR(self->kwd_mark);
1246+
Py_CLEAR(self->lru_list_elem_type);
12411247
Py_CLEAR(self->cache_info_type);
12421248
Py_CLEAR(self->dict);
12431249
lru_cache_clear_list(list);
@@ -1330,6 +1336,8 @@ lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
13301336
}
13311337
Py_VISIT(self->func);
13321338
Py_VISIT(self->cache);
1339+
Py_VISIT(self->kwd_mark);
1340+
Py_VISIT(self->lru_list_elem_type);
13331341
Py_VISIT(self->cache_info_type);
13341342
Py_VISIT(self->dict);
13351343
return 0;

0 commit comments

Comments
 (0)