]> granicus.if.org Git - python/commitdiff
Remove types from type_list if they have no objects
authorMartin v. Löwis <martin@v.loewis.de>
Tue, 18 Apr 2006 06:24:08 +0000 (06:24 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Tue, 18 Apr 2006 06:24:08 +0000 (06:24 +0000)
and unlist_types_without_objects is set.
Give dump_counts a FILE* argument.

Include/object.h
Misc/NEWS
Objects/object.c
Python/pythonrun.c

index c6d0fc39516f0e386cb08a323cb2c629d023201b..4b0e08010dbbc17094f189dcbbb388e0c47af7a7 100644 (file)
@@ -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
index 2af861680df0897b91a5a0efe64f1ae6733a322d..a2e9e3a0867663e162ae0f33d2b1e0c0b43de092 100644 (file)
--- 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.
index d3dda1b028e836eecbd381550fd25bd46420613c..eac447041d5cb24d7e59bfe5b987a18678b66ef1 100644 (file)
@@ -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
index b98d6fb991bba5508420bf0970aeb22e9d8e2542..0a8180901589f59e30a80d922833e258066cc3a8 100644 (file)
@@ -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();