aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c37
-rw-r--r--Objects/listobject.c32
2 files changed, 67 insertions, 2 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 1bc7184439d..3365c4757c1 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -163,6 +163,22 @@ show_counts(void)
}
#endif
+/* Debug statistic to compare allocations with reuse through the free list */
+#undef SHOW_ALLOC_COUNT
+#ifdef SHOW_ALLOC_COUNT
+static size_t count_alloc = 0;
+static size_t count_reuse = 0;
+
+static void
+show_alloc(void)
+{
+ fprintf(stderr, "Dict allocations: %zd\n", count_alloc);
+ fprintf(stderr, "Dict reuse through freelist: %zd\n", count_reuse);
+ fprintf(stderr, "%.2f%% reuse rate\n\n",
+ (100.0*count_reuse/(count_alloc+count_reuse)));
+}
+#endif
+
/* Initialization macros.
There are two ways to create a dict: PyDict_New() is the main C API
function, and the tp_new slot maps to dict_new(). In the latter case we
@@ -190,6 +206,18 @@ show_counts(void)
static PyDictObject *free_list[PyDict_MAXFREELIST];
static int numfree = 0;
+void
+PyDict_Fini(void)
+{
+ PyDictObject *op;
+
+ while (numfree) {
+ op = free_list[--numfree];
+ assert(PyDict_CheckExact(op));
+ PyObject_GC_Del(op);
+ }
+}
+
PyObject *
PyDict_New(void)
{
@@ -201,6 +229,9 @@ PyDict_New(void)
#ifdef SHOW_CONVERSION_COUNTS
Py_AtExit(show_counts);
#endif
+#ifdef SHOW_ALLOC_COUNT
+ Py_AtExit(show_alloc);
+#endif
}
if (numfree) {
mp = free_list[--numfree];
@@ -213,11 +244,17 @@ PyDict_New(void)
assert (mp->ma_used == 0);
assert (mp->ma_table == mp->ma_smalltable);
assert (mp->ma_mask == PyDict_MINSIZE - 1);
+#ifdef SHOW_ALLOC_COUNT
+ count_reuse++;
+#endif
} else {
mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
if (mp == NULL)
return NULL;
EMPTY_TO_MINSIZE(mp);
+#ifdef SHOW_ALLOC_COUNT
+ count_alloc++;
+#endif
}
mp->ma_lookup = lookdict_unicode;
#ifdef SHOW_CONVERSION_COUNTS
diff --git a/Objects/listobject.c b/Objects/listobject.c
index cb0609ac4d7..d2917d2caa9 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -63,6 +63,22 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
return 0;
}
+/* Debug statistic to compare allocations with reuse through the free list */
+#undef SHOW_ALLOC_COUNT
+#ifdef SHOW_ALLOC_COUNT
+static size_t count_alloc = 0;
+static size_t count_reuse = 0;
+
+static void
+show_alloc(void)
+{
+ fprintf(stderr, "List allocations: %zd\n", count_alloc);
+ fprintf(stderr, "List reuse through freelist: %zd\n", count_reuse);
+ fprintf(stderr, "%.2f%% reuse rate\n\n",
+ (100.0*count_reuse/(count_alloc+count_reuse)));
+}
+#endif
+
/* Empty list reuse scheme to save calls to malloc and free */
#ifndef PyList_MAXFREELIST
#define PyList_MAXFREELIST 80
@@ -76,8 +92,7 @@ PyList_Fini(void)
PyListObject *op;
while (numfree) {
- numfree--;
- op = free_list[numfree];
+ op = free_list[--numfree];
assert(PyList_CheckExact(op));
PyObject_GC_Del(op);
}
@@ -88,6 +103,13 @@ PyList_New(Py_ssize_t size)
{
PyListObject *op;
size_t nbytes;
+#ifdef SHOW_ALLOC_COUNT
+ static int initialized = 0;
+ if (!initialized) {
+ Py_AtExit(show_alloc);
+ initialized = 1;
+ }
+#endif
if (size < 0) {
PyErr_BadInternalCall();
@@ -101,10 +123,16 @@ PyList_New(Py_ssize_t size)
numfree--;
op = free_list[numfree];
_Py_NewReference((PyObject *)op);
+#ifdef SHOW_ALLOC_COUNT
+ count_reuse++;
+#endif
} else {
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL)
return NULL;
+#ifdef SHOW_ALLOC_COUNT
+ count_alloc++;
+#endif
}
if (size <= 0)
op->ob_item = NULL;