From b4ee4a16f4fc28d89ba9b139db6cbaace44fc47a Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 7 Feb 2008 17:15:30 +0000 Subject: [PATCH] Added some statistics code to dict and list object code. I wanted to test how a larger freelist affects the reusage of freed objects. Contrary to my gut feelings 80 objects is more than fine for small apps. I haven't profiled a large app yet. --- Objects/dictobject.c | 25 +++++++++++++++++++++++++ Objects/listobject.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index e0ac475346a..82d247f3f95 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -162,6 +162,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 @@ -199,6 +215,9 @@ PyDict_New(void) return NULL; #ifdef SHOW_CONVERSION_COUNTS Py_AtExit(show_counts); +#endif +#ifdef SHOW_ALLOC_COUNT + Py_AtExit(show_alloc); #endif } if (numfree) { @@ -212,11 +231,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_string; #ifdef SHOW_CONVERSION_COUNTS diff --git a/Objects/listobject.c b/Objects/listobject.c index 9e893662b35..df7a405f1f4 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 @@ -88,6 +104,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 +124,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;