Blame SOURCES/00147-add-debug-malloc-stats.patch

23b3e9
diff -up Python-2.7.2/Include/dictobject.h.add-debug-malloc-stats Python-2.7.2/Include/dictobject.h
23b3e9
--- Python-2.7.2/Include/dictobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/dictobject.h	2011-09-16 19:03:25.105821625 -0400
23b3e9
@@ -150,6 +150,8 @@ PyAPI_FUNC(PyObject *) PyDict_GetItemStr
23b3e9
 PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item);
23b3e9
 PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key);
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out);
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Include/floatobject.h.add-debug-malloc-stats Python-2.7.2/Include/floatobject.h
23b3e9
--- Python-2.7.2/Include/floatobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/floatobject.h	2011-09-16 19:03:25.106821625 -0400
23b3e9
@@ -132,6 +132,7 @@ PyAPI_FUNC(PyObject *) _PyFloat_FormatAd
23b3e9
    failure.  Used in builtin_round in bltinmodule.c. */
23b3e9
 PyAPI_FUNC(PyObject *) _Py_double_round(double x, int ndigits);
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out);
23b3e9
 
23b3e9
 
23b3e9
 #ifdef __cplusplus
23b3e9
diff -up Python-2.7.2/Include/frameobject.h.add-debug-malloc-stats Python-2.7.2/Include/frameobject.h
23b3e9
--- Python-2.7.2/Include/frameobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/frameobject.h	2011-09-16 19:03:25.107821625 -0400
23b3e9
@@ -80,6 +80,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(Py
23b3e9
 
23b3e9
 PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
23b3e9
+
23b3e9
 /* Return the line of code the frame is currently executing. */
23b3e9
 PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
23b3e9
 
23b3e9
diff -up Python-2.7.2/Include/intobject.h.add-debug-malloc-stats Python-2.7.2/Include/intobject.h
23b3e9
--- Python-2.7.2/Include/intobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/intobject.h	2011-09-16 19:03:25.107821625 -0400
23b3e9
@@ -74,6 +74,8 @@ PyAPI_FUNC(PyObject *) _PyInt_FormatAdva
23b3e9
 					     char *format_spec,
23b3e9
 					     Py_ssize_t format_spec_len);
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyInt_DebugMallocStats(FILE *out);
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Include/listobject.h.add-debug-malloc-stats Python-2.7.2/Include/listobject.h
23b3e9
--- Python-2.7.2/Include/listobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/listobject.h	2011-09-16 19:03:25.107821625 -0400
23b3e9
@@ -62,6 +62,8 @@ PyAPI_FUNC(PyObject *) _PyList_Extend(Py
23b3e9
 #define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v))
23b3e9
 #define PyList_GET_SIZE(op)    Py_SIZE(op)
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out);
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Include/methodobject.h.add-debug-malloc-stats Python-2.7.2/Include/methodobject.h
23b3e9
--- Python-2.7.2/Include/methodobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/methodobject.h	2011-09-16 19:03:25.108821625 -0400
23b3e9
@@ -87,6 +87,10 @@ typedef struct {
23b3e9
 
23b3e9
 PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out);
23b3e9
+PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out);
23b3e9
+
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Include/object.h.add-debug-malloc-stats Python-2.7.2/Include/object.h
23b3e9
--- Python-2.7.2/Include/object.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/object.h	2011-09-16 19:03:25.108821625 -0400
23b3e9
@@ -980,6 +980,13 @@ PyAPI_DATA(PyObject *) _PyTrash_delete_l
23b3e9
             _PyTrash_thread_deposit_object((PyObject*)op); \
23b3e9
     } while (0);
23b3e9
 
23b3e9
+PyAPI_FUNC(void)
23b3e9
+_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks,
23b3e9
+		       size_t sizeof_block);
23b3e9
+
23b3e9
+PyAPI_FUNC(void)
23b3e9
+_PyObject_DebugTypeStats(FILE *out);
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Include/objimpl.h.add-debug-malloc-stats Python-2.7.2/Include/objimpl.h
23b3e9
--- Python-2.7.2/Include/objimpl.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/objimpl.h	2011-09-16 19:03:25.108821625 -0400
23b3e9
@@ -101,13 +101,13 @@ PyAPI_FUNC(void) PyObject_Free(void *);
23b3e9
 
23b3e9
 /* Macros */
23b3e9
 #ifdef WITH_PYMALLOC
23b3e9
+PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out);
23b3e9
 #ifdef PYMALLOC_DEBUG   /* WITH_PYMALLOC && PYMALLOC_DEBUG */
23b3e9
 PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes);
23b3e9
 PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes);
23b3e9
 PyAPI_FUNC(void) _PyObject_DebugFree(void *p);
23b3e9
 PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p);
23b3e9
 PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p);
23b3e9
-PyAPI_FUNC(void) _PyObject_DebugMallocStats(void);
23b3e9
 PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes);
23b3e9
 PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes);
23b3e9
 PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p);
23b3e9
diff -up Python-2.7.2/Include/stringobject.h.add-debug-malloc-stats Python-2.7.2/Include/stringobject.h
23b3e9
--- Python-2.7.2/Include/stringobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/stringobject.h	2011-09-16 19:03:25.109821625 -0400
23b3e9
@@ -204,6 +204,8 @@ PyAPI_FUNC(PyObject *) _PyBytes_FormatAd
23b3e9
 					       char *format_spec,
23b3e9
 					       Py_ssize_t format_spec_len);
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyString_DebugMallocStats(FILE *out);
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Include/unicodeobject.h.add-debug-malloc-stats Python-2.7.2/Include/unicodeobject.h
23b3e9
--- Python-2.7.2/Include/unicodeobject.h.add-debug-malloc-stats	2011-06-11 11:46:23.000000000 -0400
23b3e9
+++ Python-2.7.2/Include/unicodeobject.h	2011-09-16 19:03:25.109821625 -0400
23b3e9
@@ -1406,6 +1406,8 @@ PyAPI_FUNC(int) _PyUnicode_IsAlpha(
23b3e9
     Py_UNICODE ch       /* Unicode character */
23b3e9
     );
23b3e9
 
23b3e9
+PyAPI_FUNC(void) _PyUnicode_DebugMallocStats(FILE *out);
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Lib/test/test_sys.py.add-debug-malloc-stats Python-2.7.2/Lib/test/test_sys.py
23b3e9
--- Python-2.7.2/Lib/test/test_sys.py.add-debug-malloc-stats	2011-09-16 19:03:25.048821626 -0400
23b3e9
+++ Python-2.7.2/Lib/test/test_sys.py	2011-09-16 19:03:25.110821625 -0400
23b3e9
@@ -473,6 +473,32 @@ class SysModuleTest(unittest.TestCase):
23b3e9
         p.wait()
23b3e9
         self.assertIn(executable, ["''", repr(sys.executable)])
23b3e9
 
23b3e9
+    def test_debugmallocstats(self):
23b3e9
+        # Test sys._debugmallocstats()
23b3e9
+
23b3e9
+        import subprocess
23b3e9
+
23b3e9
+        # Verify the default of writing to stderr:
23b3e9
+        p = subprocess.Popen([sys.executable,
23b3e9
+                              '-c', 'import sys; sys._debugmallocstats()'],
23b3e9
+                             stderr=subprocess.PIPE)
23b3e9
+        out, err = p.communicate()
23b3e9
+        p.wait()
23b3e9
+        self.assertIn("arenas allocated current", err)
23b3e9
+                                     
23b3e9
+        # Verify that we can redirect the output to a file (not a file-like
23b3e9
+        # object, though):
23b3e9
+        with open('mallocstats.txt', 'w') as out:
23b3e9
+            sys._debugmallocstats(out)
23b3e9
+        result = open('mallocstats.txt').read()
23b3e9
+        self.assertIn("arenas allocated current", result)
23b3e9
+        os.unlink('mallocstats.txt')
23b3e9
+
23b3e9
+        # Verify that the destination must be a file:
23b3e9
+        with self.assertRaises(TypeError):
23b3e9
+            sys._debugmallocstats(42)
23b3e9
+        
23b3e9
+
21eb11
 @test.test_support.cpython_only
23b3e9
 class SizeofTest(unittest.TestCase):
21eb11
23b3e9
diff -up Python-2.7.2/Objects/classobject.c.add-debug-malloc-stats Python-2.7.2/Objects/classobject.c
23b3e9
--- Python-2.7.2/Objects/classobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/classobject.c	2011-09-16 19:03:25.110821625 -0400
23b3e9
@@ -2670,3 +2670,12 @@ PyMethod_Fini(void)
23b3e9
 {
23b3e9
     (void)PyMethod_ClearFreeList();
23b3e9
 }
23b3e9
+
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyMethod_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyDebugAllocatorStats(out,
23b3e9
+                           "free PyMethodObject",
23b3e9
+                           numfree, sizeof(PyMethodObject));
23b3e9
+}
23b3e9
diff -up Python-2.7.2/Objects/dictobject.c.add-debug-malloc-stats Python-2.7.2/Objects/dictobject.c
23b3e9
--- Python-2.7.2/Objects/dictobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/dictobject.c	2011-09-16 19:03:25.111821625 -0400
23b3e9
@@ -225,6 +225,15 @@ show_track(void)
23b3e9
 static PyDictObject *free_list[PyDict_MAXFREELIST];
23b3e9
 static int numfree = 0;
23b3e9
 
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyDict_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyDebugAllocatorStats(out,
23b3e9
+                           "free PyDictObject", numfree, sizeof(PyDictObject));
23b3e9
+}
23b3e9
+
23b3e9
+
23b3e9
 void
23b3e9
 PyDict_Fini(void)
23b3e9
 {
23b3e9
diff -up Python-2.7.2/Objects/floatobject.c.add-debug-malloc-stats Python-2.7.2/Objects/floatobject.c
23b3e9
--- Python-2.7.2/Objects/floatobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/floatobject.c	2011-09-16 19:03:25.111821625 -0400
23b3e9
@@ -35,6 +35,22 @@ typedef struct _floatblock PyFloatBlock;
23b3e9
 static PyFloatBlock *block_list = NULL;
23b3e9
 static PyFloatObject *free_list = NULL;
23b3e9
 
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyFloat_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+  int num_blocks = 0;
23b3e9
+  PyFloatBlock *block;
23b3e9
+
23b3e9
+  /* Walk the block list, counting */
23b3e9
+  for (block = block_list; block ; block = block->next) {
23b3e9
+      num_blocks++;
23b3e9
+  }
23b3e9
+
23b3e9
+  _PyDebugAllocatorStats(out,
23b3e9
+                         "PyFloatBlock", num_blocks, sizeof(PyFloatBlock));
23b3e9
+}
23b3e9
+
23b3e9
 static PyFloatObject *
23b3e9
 fill_free_list(void)
23b3e9
 {
23b3e9
diff -up Python-2.7.2/Objects/frameobject.c.add-debug-malloc-stats Python-2.7.2/Objects/frameobject.c
23b3e9
--- Python-2.7.2/Objects/frameobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/frameobject.c	2011-09-16 19:03:25.112821625 -0400
23b3e9
@@ -980,3 +980,13 @@ PyFrame_Fini(void)
23b3e9
     Py_XDECREF(builtin_object);
23b3e9
     builtin_object = NULL;
23b3e9
 }
23b3e9
+
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyFrame_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyDebugAllocatorStats(out,
23b3e9
+                           "free PyFrameObject",
23b3e9
+                           numfree, sizeof(PyFrameObject));
23b3e9
+}
23b3e9
+
23b3e9
diff -up Python-2.7.2/Objects/intobject.c.add-debug-malloc-stats Python-2.7.2/Objects/intobject.c
23b3e9
--- Python-2.7.2/Objects/intobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/intobject.c	2011-09-16 19:03:25.112821625 -0400
23b3e9
@@ -44,6 +44,23 @@ typedef struct _intblock PyIntBlock;
23b3e9
 static PyIntBlock *block_list = NULL;
23b3e9
 static PyIntObject *free_list = NULL;
23b3e9
 
23b3e9
+
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyInt_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    int num_blocks = 0;
23b3e9
+    PyIntBlock *block;
23b3e9
+
23b3e9
+    /* Walk the block list, counting */
23b3e9
+    for (block = block_list; block ; block = block->next) {
23b3e9
+        num_blocks++;
23b3e9
+    }
23b3e9
+
23b3e9
+    _PyDebugAllocatorStats(out,
23b3e9
+                           "PyIntBlock", num_blocks, sizeof(PyIntBlock));
23b3e9
+}
23b3e9
+
23b3e9
 static PyIntObject *
23b3e9
 fill_free_list(void)
23b3e9
 {
23b3e9
diff -up Python-2.7.2/Objects/listobject.c.add-debug-malloc-stats Python-2.7.2/Objects/listobject.c
23b3e9
--- Python-2.7.2/Objects/listobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/listobject.c	2011-09-16 19:03:25.113821625 -0400
23b3e9
@@ -109,6 +109,15 @@ PyList_Fini(void)
23b3e9
     }
23b3e9
 }
23b3e9
 
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyList_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyDebugAllocatorStats(out,
23b3e9
+                           "free PyListObject",
23b3e9
+                           numfree, sizeof(PyListObject));
23b3e9
+}
23b3e9
+
23b3e9
 PyObject *
23b3e9
 PyList_New(Py_ssize_t size)
23b3e9
 {
23b3e9
diff -up Python-2.7.2/Objects/methodobject.c.add-debug-malloc-stats Python-2.7.2/Objects/methodobject.c
23b3e9
--- Python-2.7.2/Objects/methodobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/methodobject.c	2011-09-16 19:03:25.113821625 -0400
23b3e9
@@ -412,6 +412,15 @@ PyCFunction_Fini(void)
23b3e9
     (void)PyCFunction_ClearFreeList();
23b3e9
 }
23b3e9
 
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyCFunction_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyDebugAllocatorStats(out,
23b3e9
+                           "free PyCFunction",
23b3e9
+                           numfree, sizeof(PyCFunction));
23b3e9
+}
23b3e9
+
23b3e9
 /* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
23b3e9
    but it's part of the API so we need to keep a function around that
23b3e9
    existing C extensions can call.
23b3e9
diff -up Python-2.7.2/Objects/object.c.add-debug-malloc-stats Python-2.7.2/Objects/object.c
23b3e9
--- Python-2.7.2/Objects/object.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/object.c	2011-09-16 19:04:46.463820849 -0400
23b3e9
@@ -2334,6 +2334,23 @@ PyMem_Free(void *p)
23b3e9
     PyMem_FREE(p);
23b3e9
 }
23b3e9
 
23b3e9
+void
23b3e9
+_PyObject_DebugTypeStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyString_DebugMallocStats(out);
23b3e9
+    _PyCFunction_DebugMallocStats(out);
23b3e9
+    _PyDict_DebugMallocStats(out);
23b3e9
+    _PyFloat_DebugMallocStats(out);
23b3e9
+    _PyFrame_DebugMallocStats(out);
23b3e9
+    _PyInt_DebugMallocStats(out);
23b3e9
+    _PyList_DebugMallocStats(out);
23b3e9
+    _PyMethod_DebugMallocStats(out);
23b3e9
+    _PySet_DebugMallocStats(out);
23b3e9
+    _PyTuple_DebugMallocStats(out);
23b3e9
+#if Py_USING_UNICODE
23b3e9
+    _PyUnicode_DebugMallocStats(out);
23b3e9
+#endif
23b3e9
+}
23b3e9
 
23b3e9
 /* These methods are used to control infinite recursion in repr, str, print,
23b3e9
    etc.  Container objects that may recursively contain themselves,
23b3e9
diff -up Python-2.7.2/Objects/obmalloc.c.add-debug-malloc-stats Python-2.7.2/Objects/obmalloc.c
23b3e9
--- Python-2.7.2/Objects/obmalloc.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/obmalloc.c	2011-09-16 19:03:25.114821625 -0400
23b3e9
@@ -508,12 +508,10 @@ static struct arena_object* usable_arena
23b3e9
 /* Number of arenas allocated that haven't been free()'d. */
23b3e9
 static size_t narenas_currently_allocated = 0;
23b3e9
 
23b3e9
-#ifdef PYMALLOC_DEBUG
23b3e9
 /* Total number of times malloc() called to allocate an arena. */
23b3e9
 static size_t ntimes_arena_allocated = 0;
23b3e9
 /* High water mark (max value ever seen) for narenas_currently_allocated. */
23b3e9
 static size_t narenas_highwater = 0;
23b3e9
-#endif
23b3e9
 
23b3e9
 /* Allocate a new arena.  If we run out of memory, return NULL.  Else
23b3e9
  * allocate a new arena, and return the address of an arena_object
23b3e9
@@ -528,7 +526,7 @@ new_arena(void)
23b3e9
 
23b3e9
 #ifdef PYMALLOC_DEBUG
23b3e9
     if (Py_GETENV("PYTHONMALLOCSTATS"))
23b3e9
-        _PyObject_DebugMallocStats();
23b3e9
+        _PyObject_DebugMallocStats(stderr);
23b3e9
 #endif
23b3e9
     if (unused_arena_objects == NULL) {
23b3e9
         uint i;
23b3e9
@@ -588,11 +586,9 @@ new_arena(void)
21eb11
     arenaobj->address = (uptr)address;
23b3e9
 
23b3e9
     ++narenas_currently_allocated;
23b3e9
-#ifdef PYMALLOC_DEBUG
23b3e9
     ++ntimes_arena_allocated;
23b3e9
     if (narenas_currently_allocated > narenas_highwater)
23b3e9
         narenas_highwater = narenas_currently_allocated;
23b3e9
-#endif
23b3e9
     arenaobj->freepools = NULL;
23b3e9
     /* pool_address <- first pool-aligned address in the arena
23b3e9
        nfreepools <- number of whole pools that fit after alignment */
23b3e9
@@ -1694,17 +1690,19 @@ _PyObject_DebugDumpAddress(const void *p
23b3e9
     }
23b3e9
 }
23b3e9
 
23b3e9
+#endif  /* PYMALLOC_DEBUG */
23b3e9
+
23b3e9
 static size_t
23b3e9
-printone(const char* msg, size_t value)
23b3e9
+printone(FILE *out, const char* msg, size_t value)
23b3e9
 {
23b3e9
     int i, k;
23b3e9
     char buf[100];
23b3e9
     size_t origvalue = value;
23b3e9
 
23b3e9
-    fputs(msg, stderr);
23b3e9
+    fputs(msg, out);
23b3e9
     for (i = (int)strlen(msg); i < 35; ++i)
23b3e9
-        fputc(' ', stderr);
23b3e9
-    fputc('=', stderr);
23b3e9
+        fputc(' ', out);
23b3e9
+    fputc('=', out);
23b3e9
 
23b3e9
     /* Write the value with commas. */
23b3e9
     i = 22;
23b3e9
@@ -1725,17 +1723,32 @@ printone(const char* msg, size_t value)
23b3e9
 
23b3e9
     while (i >= 0)
23b3e9
         buf[i--] = ' ';
23b3e9
-    fputs(buf, stderr);
23b3e9
+    fputs(buf, out);
23b3e9
 
23b3e9
     return origvalue;
23b3e9
 }
23b3e9
 
23b3e9
-/* Print summary info to stderr about the state of pymalloc's structures.
23b3e9
+void
23b3e9
+_PyDebugAllocatorStats(FILE *out,
23b3e9
+                       const char *block_name, int num_blocks, size_t sizeof_block)
23b3e9
+{
23b3e9
+       char buf1[128];
23b3e9
+       char buf2[128];
23b3e9
+       PyOS_snprintf(buf1, sizeof(buf1),
23b3e9
+                     "%d %ss * %zd bytes each",
23b3e9
+                     num_blocks, block_name, sizeof_block);
23b3e9
+       PyOS_snprintf(buf2, sizeof(buf2),
23b3e9
+                     "%48s ", buf1);
23b3e9
+      (void)printone(out, buf2, num_blocks * sizeof_block);
23b3e9
+}
23b3e9
+
23b3e9
+
23b3e9
+/* Print summary info to "out" about the state of pymalloc's structures.
23b3e9
  * In Py_DEBUG mode, also perform some expensive internal consistency
23b3e9
  * checks.
23b3e9
  */
23b3e9
 void
23b3e9
-_PyObject_DebugMallocStats(void)
23b3e9
+_PyObject_DebugMallocStats(FILE *out)
23b3e9
 {
23b3e9
     uint i;
23b3e9
     const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
23b3e9
@@ -1764,7 +1777,7 @@ _PyObject_DebugMallocStats(void)
23b3e9
     size_t total;
23b3e9
     char buf[128];
23b3e9
 
23b3e9
-    fprintf(stderr, "Small block threshold = %d, in %u size classes.\n",
23b3e9
+    fprintf(out, "Small block threshold = %d, in %u size classes.\n",
23b3e9
             SMALL_REQUEST_THRESHOLD, numclasses);
23b3e9
 
23b3e9
     for (i = 0; i < numclasses; ++i)
23b3e9
@@ -1818,10 +1831,10 @@ _PyObject_DebugMallocStats(void)
23b3e9
     }
23b3e9
     assert(narenas == narenas_currently_allocated);
23b3e9
 
23b3e9
-    fputc('\n', stderr);
23b3e9
+    fputc('\n', out);
23b3e9
     fputs("class   size   num pools   blocks in use  avail blocks\n"
23b3e9
           "-----   ----   ---------   -------------  ------------\n",
23b3e9
-          stderr);
23b3e9
+          out);
23b3e9
 
23b3e9
     for (i = 0; i < numclasses; ++i) {
23b3e9
         size_t p = numpools[i];
23b3e9
@@ -1832,7 +1845,7 @@ _PyObject_DebugMallocStats(void)
23b3e9
             assert(b == 0 && f == 0);
23b3e9
             continue;
23b3e9
         }
23b3e9
-        fprintf(stderr, "%5u %6u "
23b3e9
+        fprintf(out, "%5u %6u "
23b3e9
                         "%11" PY_FORMAT_SIZE_T "u "
23b3e9
                         "%15" PY_FORMAT_SIZE_T "u "
23b3e9
                         "%13" PY_FORMAT_SIZE_T "u\n",
23b3e9
@@ -1842,36 +1855,35 @@ _PyObject_DebugMallocStats(void)
23b3e9
         pool_header_bytes += p * POOL_OVERHEAD;
23b3e9
         quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size);
23b3e9
     }
23b3e9
-    fputc('\n', stderr);
23b3e9
-    (void)printone("# times object malloc called", serialno);
23b3e9
-
23b3e9
-    (void)printone("# arenas allocated total", ntimes_arena_allocated);
23b3e9
-    (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas);
23b3e9
-    (void)printone("# arenas highwater mark", narenas_highwater);
23b3e9
-    (void)printone("# arenas allocated current", narenas);
23b3e9
+    fputc('\n', out);
23b3e9
+#ifdef PYMALLOC_DEBUG
23b3e9
+    (void)printone(out, "# times object malloc called", serialno);
23b3e9
+#endif
23b3e9
+    (void)printone(out, "# arenas allocated total", ntimes_arena_allocated);
23b3e9
+    (void)printone(out, "# arenas reclaimed", ntimes_arena_allocated - narenas);
23b3e9
+    (void)printone(out, "# arenas highwater mark", narenas_highwater);
23b3e9
+    (void)printone(out, "# arenas allocated current", narenas);
23b3e9
 
23b3e9
     PyOS_snprintf(buf, sizeof(buf),
23b3e9
         "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena",
23b3e9
         narenas, ARENA_SIZE);
23b3e9
-    (void)printone(buf, narenas * ARENA_SIZE);
23b3e9
+    (void)printone(out, buf, narenas * ARENA_SIZE);
23b3e9
 
23b3e9
-    fputc('\n', stderr);
23b3e9
+    fputc('\n', out);
23b3e9
 
23b3e9
-    total = printone("# bytes in allocated blocks", allocated_bytes);
23b3e9
-    total += printone("# bytes in available blocks", available_bytes);
23b3e9
+    total = printone(out, "# bytes in allocated blocks", allocated_bytes);
23b3e9
+    total += printone(out, "# bytes in available blocks", available_bytes);
23b3e9
 
23b3e9
     PyOS_snprintf(buf, sizeof(buf),
23b3e9
         "%u unused pools * %d bytes", numfreepools, POOL_SIZE);
23b3e9
-    total += printone(buf, (size_t)numfreepools * POOL_SIZE);
23b3e9
+    total += printone(out, buf, (size_t)numfreepools * POOL_SIZE);
23b3e9
 
23b3e9
-    total += printone("# bytes lost to pool headers", pool_header_bytes);
23b3e9
-    total += printone("# bytes lost to quantization", quantization);
23b3e9
-    total += printone("# bytes lost to arena alignment", arena_alignment);
23b3e9
-    (void)printone("Total", total);
23b3e9
+    total += printone(out, "# bytes lost to pool headers", pool_header_bytes);
23b3e9
+    total += printone(out, "# bytes lost to quantization", quantization);
23b3e9
+    total += printone(out, "# bytes lost to arena alignment", arena_alignment);
23b3e9
+    (void)printone(out, "Total", total);
23b3e9
 }
23b3e9
 
23b3e9
-#endif  /* PYMALLOC_DEBUG */
23b3e9
-
23b3e9
 #ifdef Py_USING_MEMORY_DEBUGGER
23b3e9
 /* Make this function last so gcc won't inline it since the definition is
23b3e9
  * after the reference.
23b3e9
diff -up Python-2.7.2/Objects/setobject.c.add-debug-malloc-stats Python-2.7.2/Objects/setobject.c
23b3e9
--- Python-2.7.2/Objects/setobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/setobject.c	2011-09-16 19:03:25.115821625 -0400
23b3e9
@@ -1088,6 +1088,16 @@ PySet_Fini(void)
23b3e9
     Py_CLEAR(emptyfrozenset);
23b3e9
 }
23b3e9
 
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PySet_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyDebugAllocatorStats(out,
23b3e9
+                           "free PySetObject",
23b3e9
+                           numfree, sizeof(PySetObject));
23b3e9
+}
23b3e9
+
23b3e9
+
23b3e9
 static PyObject *
23b3e9
 set_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
23b3e9
 {
23b3e9
diff -up Python-2.7.2/Objects/stringobject.c.add-debug-malloc-stats Python-2.7.2/Objects/stringobject.c
23b3e9
--- Python-2.7.2/Objects/stringobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/stringobject.c	2011-09-16 19:03:25.116821625 -0400
23b3e9
@@ -4822,3 +4822,43 @@ void _Py_ReleaseInternedStrings(void)
23b3e9
     PyDict_Clear(interned);
23b3e9
     Py_CLEAR(interned);
23b3e9
 }
23b3e9
+
23b3e9
+void _PyString_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    ssize_t i;
23b3e9
+    int num_immortal = 0, num_mortal = 0;
23b3e9
+    ssize_t immortal_size = 0, mortal_size = 0;
23b3e9
+
23b3e9
+    if (interned == NULL || !PyDict_Check(interned))
23b3e9
+        return;
23b3e9
+
23b3e9
+    for (i = 0; i <= ((PyDictObject*)interned)->ma_mask; i++) {
23b3e9
+        PyDictEntry *ep = ((PyDictObject*)interned)->ma_table + i;
23b3e9
+        PyObject *pvalue = ep->me_value;
23b3e9
+        if (pvalue != NULL) {
23b3e9
+            PyStringObject *s = (PyStringObject *)ep->me_key;
23b3e9
+
23b3e9
+            switch (s->ob_sstate) {
23b3e9
+            case SSTATE_NOT_INTERNED:
23b3e9
+                /* XXX Shouldn't happen */
23b3e9
+                break;
23b3e9
+            case SSTATE_INTERNED_IMMORTAL:
23b3e9
+                num_immortal ++;
23b3e9
+                immortal_size += s->ob_size;
23b3e9
+                break;
23b3e9
+            case SSTATE_INTERNED_MORTAL:
23b3e9
+                num_mortal ++;
23b3e9
+                mortal_size += s->ob_size;
23b3e9
+                break;
23b3e9
+            default:
23b3e9
+                Py_FatalError("Inconsistent interned string state.");
23b3e9
+            }
23b3e9
+        }
23b3e9
+    }
23b3e9
+
23b3e9
+    fprintf(out, "%d mortal interned strings\n", num_mortal);
23b3e9
+    fprintf(out, "%d immortal interned strings\n", num_immortal);
23b3e9
+    fprintf(out, "total size of all interned strings: "
23b3e9
+            "%zi/%zi "
23b3e9
+            "mortal/immortal\n", mortal_size, immortal_size);
23b3e9
+}
23b3e9
diff -up Python-2.7.2/Objects/tupleobject.c.add-debug-malloc-stats Python-2.7.2/Objects/tupleobject.c
23b3e9
--- Python-2.7.2/Objects/tupleobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/tupleobject.c	2011-09-16 19:03:25.116821625 -0400
23b3e9
@@ -44,6 +44,22 @@ show_track(void)
23b3e9
 }
23b3e9
 #endif
23b3e9
 
23b3e9
+/* Print summary info about the state of the optimized allocator */
23b3e9
+void
23b3e9
+_PyTuple_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+#if PyTuple_MAXSAVESIZE > 0
23b3e9
+    int i;
23b3e9
+    char buf[128];
23b3e9
+    for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
23b3e9
+        PyOS_snprintf(buf, sizeof(buf),
23b3e9
+                      "free %d-sized PyTupleObject", i);
23b3e9
+        _PyDebugAllocatorStats(out,
23b3e9
+                               buf,
23b3e9
+                               numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i));
23b3e9
+    }
23b3e9
+#endif
23b3e9
+}
23b3e9
 
23b3e9
 PyObject *
23b3e9
 PyTuple_New(register Py_ssize_t size)
23b3e9
diff -up Python-2.7.2/Objects/unicodeobject.c.add-debug-malloc-stats Python-2.7.2/Objects/unicodeobject.c
23b3e9
--- Python-2.7.2/Objects/unicodeobject.c.add-debug-malloc-stats	2011-06-11 11:46:27.000000000 -0400
23b3e9
+++ Python-2.7.2/Objects/unicodeobject.c	2011-09-16 19:03:25.118821625 -0400
23b3e9
@@ -8883,6 +8883,12 @@ _PyUnicode_Fini(void)
23b3e9
     (void)PyUnicode_ClearFreeList();
23b3e9
 }
23b3e9
 
23b3e9
+void _PyUnicode_DebugMallocStats(FILE *out)
23b3e9
+{
23b3e9
+    _PyDebugAllocatorStats(out, "free PyUnicodeObject", numfree,
23b3e9
+                           sizeof(PyUnicodeObject));
23b3e9
+}
23b3e9
+
23b3e9
 #ifdef __cplusplus
23b3e9
 }
23b3e9
 #endif
23b3e9
diff -up Python-2.7.2/Python/pythonrun.c.add-debug-malloc-stats Python-2.7.2/Python/pythonrun.c
23b3e9
--- Python-2.7.2/Python/pythonrun.c.add-debug-malloc-stats	2011-09-16 19:03:25.025821626 -0400
23b3e9
+++ Python-2.7.2/Python/pythonrun.c	2011-09-16 19:03:25.118821625 -0400
23b3e9
@@ -549,7 +549,7 @@ Py_Finalize(void)
23b3e9
 #endif /* Py_TRACE_REFS */
23b3e9
 #ifdef PYMALLOC_DEBUG
23b3e9
     if (Py_GETENV("PYTHONMALLOCSTATS"))
23b3e9
-        _PyObject_DebugMallocStats();
23b3e9
+        _PyObject_DebugMallocStats(stderr);
23b3e9
 #endif
23b3e9
 
23b3e9
     call_ll_exitfuncs();
23b3e9
diff -up Python-2.7.2/Python/sysmodule.c.add-debug-malloc-stats Python-2.7.2/Python/sysmodule.c
23b3e9
--- Python-2.7.2/Python/sysmodule.c.add-debug-malloc-stats	2011-09-16 19:03:25.007821626 -0400
23b3e9
+++ Python-2.7.2/Python/sysmodule.c	2011-09-16 19:03:25.119821625 -0400
23b3e9
@@ -872,6 +872,57 @@ a 11-tuple where the entries in the tupl
23b3e9
 extern "C" {
23b3e9
 #endif
23b3e9
 
23b3e9
+static PyObject *
23b3e9
+sys_debugmallocstats(PyObject *self, PyObject *args)
23b3e9
+{
23b3e9
+    PyObject *file = NULL;
23b3e9
+    FILE *fp;
23b3e9
+
23b3e9
+    if (!PyArg_ParseTuple(args, "|O!",
23b3e9
+                          &PyFile_Type, &file)) {
23b3e9
+      return NULL;
23b3e9
+    }
23b3e9
+    if (!file) {
23b3e9
+        /* Default to sys.stderr: */
23b3e9
+      file = PySys_GetObject("stderr");
23b3e9
+      if (!file) {
23b3e9
+          PyErr_SetString(PyExc_ValueError, "sys.stderr not set");
23b3e9
+          return NULL;
23b3e9
+      }
23b3e9
+      if (!PyFile_Check(file)) {
23b3e9
+          PyErr_SetString(PyExc_TypeError, "sys.stderr is not a file");
23b3e9
+          return NULL;
23b3e9
+      }
23b3e9
+    }
23b3e9
+
23b3e9
+    Py_INCREF(file);
23b3e9
+    /* OK, we now own a ref on non-NULL "file" */
23b3e9
+
23b3e9
+    fp = PyFile_AsFile(file);
23b3e9
+    if (!fp) {
23b3e9
+        PyErr_SetString(PyExc_ValueError, "file is closed");
23b3e9
+        Py_DECREF(file);
23b3e9
+        return NULL;	
23b3e9
+    }
23b3e9
+
23b3e9
+    _PyObject_DebugMallocStats(fp);
23b3e9
+    fputc('\n', fp);
23b3e9
+    _PyObject_DebugTypeStats(fp);
23b3e9
+
23b3e9
+    Py_DECREF(file);
23b3e9
+
23b3e9
+    Py_RETURN_NONE;
23b3e9
+}
23b3e9
+PyDoc_STRVAR(debugmallocstats_doc,
23b3e9
+"_debugmallocstats([file])\n\
23b3e9
+\n\
23b3e9
+Print summary info to the given file (or sys.stderr) about the state of\n\
23b3e9
+pymalloc's structures.\n\
23b3e9
+\n\
23b3e9
+In Py_DEBUG mode, also perform some expensive internal consistency\n\
23b3e9
+checks.\n\
23b3e9
+");
23b3e9
+
23b3e9
 #ifdef Py_TRACE_REFS
23b3e9
 /* Defined in objects.c because it uses static globals if that file */
23b3e9
 extern PyObject *_Py_GetObjects(PyObject *, PyObject *);
23b3e9
@@ -970,6 +1021,8 @@ static PyMethodDef sys_methods[] = {
23b3e9
     {"settrace",        sys_settrace, METH_O, settrace_doc},
23b3e9
     {"gettrace",        sys_gettrace, METH_NOARGS, gettrace_doc},
23b3e9
     {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
23b3e9
+    {"_debugmallocstats", sys_debugmallocstats, METH_VARARGS,
23b3e9
+     debugmallocstats_doc},
23b3e9
     {NULL,              NULL}           /* sentinel */
23b3e9
 };
23b3e9