summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin v. Löwis <martin@v.loewis.de>2006-04-18 06:24:08 (GMT)
committerMartin v. Löwis <martin@v.loewis.de>2006-04-18 06:24:08 (GMT)
commit45294a9562e5c360ee8ef8498d8792e05a6eb25e (patch)
treebc3aea94480f2eb7507cf77d86a4975d29d9e871
parent041669fa67198a5bf18da962ea19edb2af3f7e9d (diff)
downloadcpython-45294a9562e5c360ee8ef8498d8792e05a6eb25e.zip
cpython-45294a9562e5c360ee8ef8498d8792e05a6eb25e.tar.gz
cpython-45294a9562e5c360ee8ef8498d8792e05a6eb25e.tar.bz2
Remove types from type_list if they have no objects
and unlist_types_without_objects is set. Give dump_counts a FILE* argument.
-rw-r--r--Include/object.h4
-rw-r--r--Misc/NEWS2
-rw-r--r--Objects/object.c39
-rw-r--r--Python/pythonrun.c11
4 files changed, 47 insertions, 9 deletions
diff --git a/Include/object.h b/Include/object.h
index c6d0fc3..4b0e080 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -339,6 +339,7 @@ typedef struct _typeobject {
Py_ssize_t tp_allocs;
Py_ssize_t tp_frees;
Py_ssize_t tp_maxalloc;
+ struct _typeobject *tp_prev;
struct _typeobject *tp_next;
#endif
} PyTypeObject;
@@ -598,8 +599,9 @@ PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
#ifdef COUNT_ALLOCS
PyAPI_FUNC(void) inc_count(PyTypeObject *);
+PyAPI_FUNC(void) dec_count(PyTypeObject *);
#define _Py_INC_TPALLOCS(OP) inc_count((OP)->ob_type)
-#define _Py_INC_TPFREES(OP) (OP)->ob_type->tp_frees++
+#define _Py_INC_TPFREES(OP) dec_count((OP)->ob_type)
#define _Py_DEC_TPFREES(OP) (OP)->ob_type->tp_frees--
#define _Py_COUNT_ALLOCS_COMMA ,
#else
diff --git a/Misc/NEWS b/Misc/NEWS
index 2af8616..a2e9e3a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,8 @@ What's New in Python 2.5 alpha 2?
Core and builtins
-----------------
+- Under COUNT_ALLOCS, types are not necessarily immortal anymore.
+
- All uses of PyStructSequence_InitType have been changed to initialize
the type objects only once, even if the interpreter is initialized
multiple times.
diff --git a/Objects/object.c b/Objects/object.c
index d3dda1b..eac4470 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -74,23 +74,30 @@ _Py_AddToAllObjects(PyObject *op, int force)
#ifdef COUNT_ALLOCS
static PyTypeObject *type_list;
+/* All types are added to type_list, atleast when
+ they get one object created. That makes them
+ immortal, which unfortunately contributes to
+ garbage itself. If unlist_types_without_objects
+ is set, they will be removed from the type_list
+ once the last object is deallocated. */
+int unlist_types_without_objects;
extern int tuple_zero_allocs, fast_tuple_allocs;
extern int quick_int_allocs, quick_neg_int_allocs;
extern int null_strings, one_strings;
void
-dump_counts(void)
+dump_counts(FILE* f)
{
PyTypeObject *tp;
for (tp = type_list; tp; tp = tp->tp_next)
- fprintf(stderr, "%s alloc'd: %d, freed: %d, max in use: %d\n",
+ fprintf(f, "%s alloc'd: %d, freed: %d, max in use: %d\n",
tp->tp_name, tp->tp_allocs, tp->tp_frees,
tp->tp_maxalloc);
- fprintf(stderr, "fast tuple allocs: %d, empty: %d\n",
+ fprintf(f, "fast tuple allocs: %d, empty: %d\n",
fast_tuple_allocs, tuple_zero_allocs);
- fprintf(stderr, "fast int allocs: pos: %d, neg: %d\n",
+ fprintf(f, "fast int allocs: pos: %d, neg: %d\n",
quick_int_allocs, quick_neg_int_allocs);
- fprintf(stderr, "null strings: %d, 1-strings: %d\n",
+ fprintf(f, "null strings: %d, 1-strings: %d\n",
null_strings, one_strings);
}
@@ -124,10 +131,12 @@ get_counts(void)
void
inc_count(PyTypeObject *tp)
{
- if (tp->tp_allocs == 0) {
+ if (tp->tp_next == NULL && tp->tp_prev == NULL) {
/* first time; insert in linked list */
if (tp->tp_next != NULL) /* sanity check */
Py_FatalError("XXX inc_count sanity check");
+ if (type_list)
+ type_list->tp_prev = tp;
tp->tp_next = type_list;
/* Note that as of Python 2.2, heap-allocated type objects
* can go away, but this code requires that they stay alive
@@ -150,6 +159,24 @@ inc_count(PyTypeObject *tp)
if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc)
tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees;
}
+
+void dec_count(PyTypeObject *tp)
+{
+ tp->tp_frees++;
+ if (unlist_types_without_objects &&
+ tp->tp_allocs == tp->tp_frees) {
+ /* unlink the type from type_list */
+ if (tp->tp_prev)
+ tp->tp_prev->tp_next = tp->tp_next;
+ else
+ type_list = tp->tp_next;
+ if (tp->tp_next)
+ tp->tp_next->tp_prev = tp->tp_prev;
+ tp->tp_next = tp->tp_prev = NULL;
+ Py_DECREF(tp);
+ }
+}
+
#endif
#ifdef Py_REF_DEBUG
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index b98d6fb..0a81809 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -311,7 +311,7 @@ Py_Initialize(void)
#ifdef COUNT_ALLOCS
-extern void dump_counts(void);
+extern void dump_counts(FILE*);
#endif
/* Undo the effect of Py_Initialize().
@@ -373,6 +373,13 @@ Py_Finalize(void)
* XXX I haven't seen a real-life report of either of these.
*/
PyGC_Collect();
+#ifdef COUNT_ALLOCS
+ /* With COUNT_ALLOCS, it helps to run GC multiple times:
+ each collection might release some types from the type
+ list, so they become garbage. */
+ while (PyGC_Collect() > 0)
+ /* nothing */;
+#endif
/* Destroy all modules */
PyImport_Cleanup();
@@ -401,7 +408,7 @@ Py_Finalize(void)
/* Debugging stuff */
#ifdef COUNT_ALLOCS
- dump_counts();
+ dump_counts(stdout);
#endif
PRINT_TOTAL_REFS();