uint64_t pyeval_calls;
} CallStats;
+typedef struct _object_stats {
+ uint64_t allocations;
+ uint64_t frees;
+ uint64_t new_values;
+ uint64_t dict_materialized_on_request;
+ uint64_t dict_materialized_new_key;
+ uint64_t dict_materialized_too_big;
+} ObjectStats;
+
typedef struct _stats {
OpcodeStats opcode_stats[256];
CallStats call_stats;
+ ObjectStats object_stats;
} PyStats;
extern PyStats _py_stats;
#define STAT_DEC(opname, name) _py_stats.opcode_stats[opname].specialization.name--
#define OPCODE_EXE_INC(opname) _py_stats.opcode_stats[opname].execution_count++
#define CALL_STAT_INC(name) _py_stats.call_stats.name++
+#define OBJECT_STAT_INC(name) _py_stats.object_stats.name++
void _Py_PrintSpecializationStats(int to_file);
#define STAT_DEC(opname, name) ((void)0)
#define OPCODE_EXE_INC(opname) ((void)0)
#define CALL_STAT_INC(name) ((void)0)
+#define OBJECT_STAT_INC(name) ((void)0)
#endif
#include "Python.h"
#include "pycore_bitutils.h" // _Py_bit_length
#include "pycore_call.h" // _PyObject_CallNoArgs()
+#include "pycore_code.h" // stats
#include "pycore_dict.h" // PyDictKeysObject
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
#include "pycore_object.h" // _PyObject_GC_TRACK()
return 0;
}
if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
+ OBJECT_STAT_INC(new_values);
return init_inline_values(obj, tp);
}
PyObject *dict;
{
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
+ OBJECT_STAT_INC(dict_materialized_on_request);
return make_dict_from_instance_attributes(keys, values);
}
PyErr_SetObject(PyExc_AttributeError, name);
return -1;
}
+#ifdef Py_STATS
+ if (shared_keys_usable_size(keys) > 14) {
+ OBJECT_STAT_INC(dict_materialized_too_big);
+ }
+ else {
+ OBJECT_STAT_INC(dict_materialized_new_key);
+ }
+#endif
PyObject *dict = make_dict_from_instance_attributes(keys, values);
if (dict == NULL) {
return -1;
PyObject **dictptr = _PyObject_ManagedDictPointer(obj);
if (*values_ptr) {
assert(*dictptr == NULL);
+ OBJECT_STAT_INC(dict_materialized_on_request);
*dictptr = dict = make_dict_from_instance_attributes(CACHED_KEYS(tp), *values_ptr);
if (dict != NULL) {
*values_ptr = NULL;
#include "Python.h"
#include "pycore_pymem.h" // _PyTraceMalloc_Config
+#include "pycore_code.h" // stats
#include <stdbool.h>
#include <stdlib.h> // malloc()
/* see PyMem_RawMalloc() */
if (size > (size_t)PY_SSIZE_T_MAX)
return NULL;
+ OBJECT_STAT_INC(allocations);
return _PyObject.malloc(_PyObject.ctx, size);
}
/* see PyMem_RawMalloc() */
if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
return NULL;
+ OBJECT_STAT_INC(allocations);
return _PyObject.calloc(_PyObject.ctx, nelem, elsize);
}
void
PyObject_Free(void *ptr)
{
+ OBJECT_STAT_INC(frees);
_PyObject.free(_PyObject.ctx, ptr);
}
fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls);
}
+static void
+print_object_stats(FILE *out, ObjectStats *stats)
+{
+ fprintf(out, "Object allocations: %" PRIu64 "\n", stats->allocations);
+ fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees);
+ fprintf(out, "Object new values: %" PRIu64 "\n", stats->new_values);
+ fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request);
+ 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);
+}
+
static void
print_stats(FILE *out, PyStats *stats) {
print_spec_stats(out, stats->opcode_stats);
print_call_stats(out, &stats->call_stats);
+ print_object_stats(out, &stats->object_stats);
}
void
total += value
for key, value in stats.items():
if "Calls to" in key:
- print(f"{key}: {value} {100*value/total:0.1f}%")
+ print(f" {key}: {value} {100*value/total:0.1f}%")
+ print("Object stats:")
+ total = stats.get("Object new values")
+ for key, value in stats.items():
+ if key.startswith("Object"):
+ if "materialize" in key:
+ print(f" {key}: {value} {100*value/total:0.1f}%")
+ else:
+ print(f" {key}: {value}")
+ total = 0
+
if __name__ == "__main__":
main()