[Python-checkins] cpython (2.7): Issue #22847: Improve method cache efficiency.
benjamin.peterson
python-checkins at python.org
Fri Feb 5 01:23:33 EST 2016
https://hg.python.org/cpython/rev/6357d851029d
changeset: 100163:6357d851029d
branch: 2.7
parent: 100161:a8aa7944c5a8
user: Antoine Pitrou <solipsis at pitrou.net>
date: Sat Nov 15 00:56:27 2014 +0100
summary:
Issue #22847: Improve method cache efficiency.
files:
Misc/NEWS | 2 +
Objects/typeobject.c | 43 ++++++++++++++++++++++++++++---
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@
Core and Builtins
-----------------
+- Issue #22847: Improve method cache efficiency.
+
- Issue #25843: When compiling code, don't merge constants if they are equal
but have a different types. For example, ``f1, f2 = lambda: 1, lambda: 1.0``
is now correctly compiled to two different functions: ``f1()`` returns ``1``
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -13,10 +13,11 @@
MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large
strings are used as attribute names. */
#define MCACHE_MAX_ATTR_SIZE 100
-#define MCACHE_SIZE_EXP 10
+#define MCACHE_SIZE_EXP 12
#define MCACHE_HASH(version, name_hash) \
- (((unsigned int)(version) * (unsigned int)(name_hash)) \
- >> (8*sizeof(unsigned int) - MCACHE_SIZE_EXP))
+ (((unsigned int)(version) ^ (unsigned int)(name_hash)) \
+ & ((1 << MCACHE_SIZE_EXP) - 1))
+
#define MCACHE_HASH_METHOD(type, name) \
MCACHE_HASH((type)->tp_version_tag, \
((PyStringObject *)(name))->ob_shash)
@@ -33,12 +34,32 @@
static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP];
static unsigned int next_version_tag = 0;
+#define MCACHE_STATS 0
+
+#if MCACHE_STATS
+static size_t method_cache_hits = 0;
+static size_t method_cache_misses = 0;
+static size_t method_cache_collisions = 0;
+#endif
+
unsigned int
PyType_ClearCache(void)
{
Py_ssize_t i;
unsigned int cur_version_tag = next_version_tag - 1;
+#if MCACHE_STATS
+ size_t total = method_cache_hits + method_cache_collisions + method_cache_misses;
+ fprintf(stderr, "-- Method cache hits = %zd (%d%%)\n",
+ method_cache_hits, (int) (100.0 * method_cache_hits / total));
+ fprintf(stderr, "-- Method cache true misses = %zd (%d%%)\n",
+ method_cache_misses, (int) (100.0 * method_cache_misses / total));
+ fprintf(stderr, "-- Method cache collisions = %zd (%d%%)\n",
+ method_cache_collisions, (int) (100.0 * method_cache_collisions / total));
+ fprintf(stderr, "-- Method cache size = %zd KB\n",
+ sizeof(method_cache) / 1024);
+#endif
+
for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
method_cache[i].version = 0;
Py_CLEAR(method_cache[i].name);
@@ -2505,8 +2526,12 @@
/* fast path */
h = MCACHE_HASH_METHOD(type, name);
if (method_cache[h].version == type->tp_version_tag &&
- method_cache[h].name == name)
+ method_cache[h].name == name) {
+#if MCACHE_STATS
+ method_cache_hits++;
+#endif
return method_cache[h].value;
+ }
}
/* Look in tp_dict of types in MRO */
@@ -2540,7 +2565,15 @@
method_cache[h].version = type->tp_version_tag;
method_cache[h].value = res; /* borrowed */
Py_INCREF(name);
- Py_SETREF(method_cache[h].name, name);
+ assert(((PyASCIIObject *)(name))->hash != -1);
+#if MCACHE_STATS
+ if (method_cache[h].name != Py_None && method_cache[h].name != name)
+ method_cache_collisions++;
+ else
+ method_cache_misses++;
+#endif
+ Py_DECREF(method_cache[h].name);
+ method_cache[h].name = name;
}
return res;
}
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list