mirror of https://github.com/python/cpython
Move stats for the method cache into the `Py_STAT` machinery (GH-100255)
This commit is contained in:
parent
bdd86741be
commit
48e352a241
|
@ -36,15 +36,9 @@ struct type_cache_entry {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MCACHE_SIZE_EXP 12
|
#define MCACHE_SIZE_EXP 12
|
||||||
#define MCACHE_STATS 0
|
|
||||||
|
|
||||||
struct type_cache {
|
struct type_cache {
|
||||||
struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP];
|
struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP];
|
||||||
#if MCACHE_STATS
|
|
||||||
size_t hits;
|
|
||||||
size_t misses;
|
|
||||||
size_t collisions;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For now we hard-code this to a value for which we are confident
|
/* For now we hard-code this to a value for which we are confident
|
||||||
|
|
|
@ -65,8 +65,15 @@ typedef struct _object_stats {
|
||||||
uint64_t dict_materialized_new_key;
|
uint64_t dict_materialized_new_key;
|
||||||
uint64_t dict_materialized_too_big;
|
uint64_t dict_materialized_too_big;
|
||||||
uint64_t dict_materialized_str_subclass;
|
uint64_t dict_materialized_str_subclass;
|
||||||
|
uint64_t type_cache_hits;
|
||||||
|
uint64_t type_cache_misses;
|
||||||
|
uint64_t type_cache_dunder_hits;
|
||||||
|
uint64_t type_cache_dunder_misses;
|
||||||
|
uint64_t type_cache_collisions;
|
||||||
} ObjectStats;
|
} ObjectStats;
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
typedef struct _stats {
|
typedef struct _stats {
|
||||||
OpcodeStats opcode_stats[256];
|
OpcodeStats opcode_stats[256];
|
||||||
CallStats call_stats;
|
CallStats call_stats;
|
||||||
|
|
|
@ -327,18 +327,6 @@ static unsigned int
|
||||||
_PyType_ClearCache(PyInterpreterState *interp)
|
_PyType_ClearCache(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
struct type_cache *cache = &interp->types.type_cache;
|
struct type_cache *cache = &interp->types.type_cache;
|
||||||
#if MCACHE_STATS
|
|
||||||
size_t total = cache->hits + cache->collisions + cache->misses;
|
|
||||||
fprintf(stderr, "-- Method cache hits = %zd (%d%%)\n",
|
|
||||||
cache->hits, (int) (100.0 * cache->hits / total));
|
|
||||||
fprintf(stderr, "-- Method cache true misses = %zd (%d%%)\n",
|
|
||||||
cache->misses, (int) (100.0 * cache->misses / total));
|
|
||||||
fprintf(stderr, "-- Method cache collisions = %zd (%d%%)\n",
|
|
||||||
cache->collisions, (int) (100.0 * cache->collisions / total));
|
|
||||||
fprintf(stderr, "-- Method cache size = %zd KiB\n",
|
|
||||||
sizeof(cache->hashtable) / 1024);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set to None, rather than NULL, so _PyType_Lookup() can
|
// Set to None, rather than NULL, so _PyType_Lookup() can
|
||||||
// use Py_SETREF() rather than using slower Py_XSETREF().
|
// use Py_SETREF() rather than using slower Py_XSETREF().
|
||||||
type_cache_clear(cache, Py_None);
|
type_cache_clear(cache, Py_None);
|
||||||
|
@ -4148,6 +4136,24 @@ done:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if the "readied" PyUnicode name
|
||||||
|
is a double-underscore special name. */
|
||||||
|
static int
|
||||||
|
is_dunder_name(PyObject *name)
|
||||||
|
{
|
||||||
|
Py_ssize_t length = PyUnicode_GET_LENGTH(name);
|
||||||
|
int kind = PyUnicode_KIND(name);
|
||||||
|
/* Special names contain at least "__x__" and are always ASCII. */
|
||||||
|
if (length > 4 && kind == PyUnicode_1BYTE_KIND) {
|
||||||
|
const Py_UCS1 *characters = PyUnicode_1BYTE_DATA(name);
|
||||||
|
return (
|
||||||
|
((characters[length-2] == '_') && (characters[length-1] == '_')) &&
|
||||||
|
((characters[0] == '_') && (characters[1] == '_'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Internal API to look for a name through the MRO.
|
/* Internal API to look for a name through the MRO.
|
||||||
This returns a borrowed reference, and doesn't set an exception! */
|
This returns a borrowed reference, and doesn't set an exception! */
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -4161,12 +4167,13 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
|
||||||
struct type_cache_entry *entry = &cache->hashtable[h];
|
struct type_cache_entry *entry = &cache->hashtable[h];
|
||||||
if (entry->version == type->tp_version_tag &&
|
if (entry->version == type->tp_version_tag &&
|
||||||
entry->name == name) {
|
entry->name == name) {
|
||||||
#if MCACHE_STATS
|
|
||||||
cache->hits++;
|
|
||||||
#endif
|
|
||||||
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
|
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
|
||||||
|
OBJECT_STAT_INC_COND(type_cache_hits, !is_dunder_name(name));
|
||||||
|
OBJECT_STAT_INC_COND(type_cache_dunder_hits, is_dunder_name(name));
|
||||||
return entry->value;
|
return entry->value;
|
||||||
}
|
}
|
||||||
|
OBJECT_STAT_INC_COND(type_cache_misses, !is_dunder_name(name));
|
||||||
|
OBJECT_STAT_INC_COND(type_cache_dunder_misses, is_dunder_name(name));
|
||||||
|
|
||||||
/* We may end up clearing live exceptions below, so make sure it's ours. */
|
/* We may end up clearing live exceptions below, so make sure it's ours. */
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
|
@ -4194,14 +4201,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
|
||||||
entry->version = type->tp_version_tag;
|
entry->version = type->tp_version_tag;
|
||||||
entry->value = res; /* borrowed */
|
entry->value = res; /* borrowed */
|
||||||
assert(_PyASCIIObject_CAST(name)->hash != -1);
|
assert(_PyASCIIObject_CAST(name)->hash != -1);
|
||||||
#if MCACHE_STATS
|
OBJECT_STAT_INC_COND(type_cache_collisions, entry->name != Py_None && entry->name != name);
|
||||||
if (entry->name != Py_None && entry->name != name) {
|
|
||||||
cache->collisions++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cache->misses++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
|
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
|
||||||
Py_SETREF(entry->name, Py_NewRef(name));
|
Py_SETREF(entry->name, Py_NewRef(name));
|
||||||
}
|
}
|
||||||
|
@ -4218,24 +4218,6 @@ _PyType_LookupId(PyTypeObject *type, _Py_Identifier *name)
|
||||||
return _PyType_Lookup(type, oname);
|
return _PyType_Lookup(type, oname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the "readied" PyUnicode name
|
|
||||||
is a double-underscore special name. */
|
|
||||||
static int
|
|
||||||
is_dunder_name(PyObject *name)
|
|
||||||
{
|
|
||||||
Py_ssize_t length = PyUnicode_GET_LENGTH(name);
|
|
||||||
int kind = PyUnicode_KIND(name);
|
|
||||||
/* Special names contain at least "__x__" and are always ASCII. */
|
|
||||||
if (length > 4 && kind == PyUnicode_1BYTE_KIND) {
|
|
||||||
const Py_UCS1 *characters = PyUnicode_1BYTE_DATA(name);
|
|
||||||
return (
|
|
||||||
((characters[length-2] == '_') && (characters[length-1] == '_')) &&
|
|
||||||
((characters[0] == '_') && (characters[1] == '_'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is similar to PyObject_GenericGetAttr(),
|
/* This is similar to PyObject_GenericGetAttr(),
|
||||||
but uses _PyType_Lookup() instead of just looking in type->tp_dict. */
|
but uses _PyType_Lookup() instead of just looking in type->tp_dict. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
|
@ -187,6 +187,11 @@ print_object_stats(FILE *out, ObjectStats *stats)
|
||||||
fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key);
|
fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key);
|
||||||
fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big);
|
fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big);
|
||||||
fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass);
|
fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass);
|
||||||
|
fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits);
|
||||||
|
fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses);
|
||||||
|
fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions);
|
||||||
|
fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits);
|
||||||
|
fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue