1 diff -up Python-2.7.2/Include/dictobject.h.add-debug-malloc-stats Python-2.7.2/Include/dictobject.h
2 --- Python-2.7.2/Include/dictobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
3 +++ Python-2.7.2/Include/dictobject.h 2011-09-16 19:03:25.105821625 -0400
4 @@ -150,6 +150,8 @@ PyAPI_FUNC(PyObject *) PyDict_GetItemStr
5 PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item);
6 PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key);
8 +PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out);
13 diff -up Python-2.7.2/Include/floatobject.h.add-debug-malloc-stats Python-2.7.2/Include/floatobject.h
14 --- Python-2.7.2/Include/floatobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
15 +++ Python-2.7.2/Include/floatobject.h 2011-09-16 19:03:25.106821625 -0400
16 @@ -132,6 +132,7 @@ PyAPI_FUNC(PyObject *) _PyFloat_FormatAd
17 failure. Used in builtin_round in bltinmodule.c. */
18 PyAPI_FUNC(PyObject *) _Py_double_round(double x, int ndigits);
20 +PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out);
24 diff -up Python-2.7.2/Include/frameobject.h.add-debug-malloc-stats Python-2.7.2/Include/frameobject.h
25 --- Python-2.7.2/Include/frameobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
26 +++ Python-2.7.2/Include/frameobject.h 2011-09-16 19:03:25.107821625 -0400
27 @@ -80,6 +80,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(Py
29 PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
31 +PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
33 /* Return the line of code the frame is currently executing. */
34 PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
36 diff -up Python-2.7.2/Include/intobject.h.add-debug-malloc-stats Python-2.7.2/Include/intobject.h
37 --- Python-2.7.2/Include/intobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
38 +++ Python-2.7.2/Include/intobject.h 2011-09-16 19:03:25.107821625 -0400
39 @@ -74,6 +74,8 @@ PyAPI_FUNC(PyObject *) _PyInt_FormatAdva
41 Py_ssize_t format_spec_len);
43 +PyAPI_FUNC(void) _PyInt_DebugMallocStats(FILE *out);
48 diff -up Python-2.7.2/Include/listobject.h.add-debug-malloc-stats Python-2.7.2/Include/listobject.h
49 --- Python-2.7.2/Include/listobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
50 +++ Python-2.7.2/Include/listobject.h 2011-09-16 19:03:25.107821625 -0400
51 @@ -62,6 +62,8 @@ PyAPI_FUNC(PyObject *) _PyList_Extend(Py
52 #define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v))
53 #define PyList_GET_SIZE(op) Py_SIZE(op)
55 +PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out);
60 diff -up Python-2.7.2/Include/methodobject.h.add-debug-malloc-stats Python-2.7.2/Include/methodobject.h
61 --- Python-2.7.2/Include/methodobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
62 +++ Python-2.7.2/Include/methodobject.h 2011-09-16 19:03:25.108821625 -0400
63 @@ -87,6 +87,10 @@ typedef struct {
65 PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);
67 +PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out);
68 +PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out);
74 diff -up Python-2.7.2/Include/object.h.add-debug-malloc-stats Python-2.7.2/Include/object.h
75 --- Python-2.7.2/Include/object.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
76 +++ Python-2.7.2/Include/object.h 2011-09-16 19:03:25.108821625 -0400
77 @@ -980,6 +980,13 @@ PyAPI_DATA(PyObject *) _PyTrash_delete_l
78 _PyTrash_thread_deposit_object((PyObject*)op); \
82 +_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks,
83 + size_t sizeof_block);
86 +_PyObject_DebugTypeStats(FILE *out);
91 diff -up Python-2.7.2/Include/objimpl.h.add-debug-malloc-stats Python-2.7.2/Include/objimpl.h
92 --- Python-2.7.2/Include/objimpl.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
93 +++ Python-2.7.2/Include/objimpl.h 2011-09-16 19:03:25.108821625 -0400
94 @@ -101,13 +101,13 @@ PyAPI_FUNC(void) PyObject_Free(void *);
98 +PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out);
99 #ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */
100 PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes);
101 PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes);
102 PyAPI_FUNC(void) _PyObject_DebugFree(void *p);
103 PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p);
104 PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p);
105 -PyAPI_FUNC(void) _PyObject_DebugMallocStats(void);
106 PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes);
107 PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes);
108 PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p);
109 diff -up Python-2.7.2/Include/stringobject.h.add-debug-malloc-stats Python-2.7.2/Include/stringobject.h
110 --- Python-2.7.2/Include/stringobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
111 +++ Python-2.7.2/Include/stringobject.h 2011-09-16 19:03:25.109821625 -0400
112 @@ -204,6 +204,8 @@ PyAPI_FUNC(PyObject *) _PyBytes_FormatAd
114 Py_ssize_t format_spec_len);
116 +PyAPI_FUNC(void) _PyString_DebugMallocStats(FILE *out);
121 diff -up Python-2.7.2/Include/unicodeobject.h.add-debug-malloc-stats Python-2.7.2/Include/unicodeobject.h
122 --- Python-2.7.2/Include/unicodeobject.h.add-debug-malloc-stats 2011-06-11 11:46:23.000000000 -0400
123 +++ Python-2.7.2/Include/unicodeobject.h 2011-09-16 19:03:25.109821625 -0400
124 @@ -1406,6 +1406,8 @@ PyAPI_FUNC(int) _PyUnicode_IsAlpha(
125 Py_UNICODE ch /* Unicode character */
128 +PyAPI_FUNC(void) _PyUnicode_DebugMallocStats(FILE *out);
133 diff -up Python-2.7.2/Lib/test/test_sys.py.add-debug-malloc-stats Python-2.7.2/Lib/test/test_sys.py
134 --- Python-2.7.2/Lib/test/test_sys.py.add-debug-malloc-stats 2011-09-16 19:03:25.048821626 -0400
135 +++ Python-2.7.2/Lib/test/test_sys.py 2011-09-16 19:03:25.110821625 -0400
136 @@ -473,6 +473,32 @@ class SysModuleTest(unittest.TestCase):
138 self.assertIn(executable, ["''", repr(sys.executable)])
140 + def test_debugmallocstats(self):
141 + # Test sys._debugmallocstats()
145 + # Verify the default of writing to stderr:
146 + p = subprocess.Popen([sys.executable,
147 + '-c', 'import sys; sys._debugmallocstats()'],
148 + stderr=subprocess.PIPE)
149 + out, err = p.communicate()
151 + self.assertIn("arenas allocated current", err)
153 + # Verify that we can redirect the output to a file (not a file-like
155 + with open('mallocstats.txt', 'w') as out:
156 + sys._debugmallocstats(out)
157 + result = open('mallocstats.txt').read()
158 + self.assertIn("arenas allocated current", result)
159 + os.unlink('mallocstats.txt')
161 + # Verify that the destination must be a file:
162 + with self.assertRaises(TypeError):
163 + sys._debugmallocstats(42)
166 @test.test_support.cpython_only
167 class SizeofTest(unittest.TestCase):
169 diff -up Python-2.7.2/Objects/classobject.c.add-debug-malloc-stats Python-2.7.2/Objects/classobject.c
170 --- Python-2.7.2/Objects/classobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
171 +++ Python-2.7.2/Objects/classobject.c 2011-09-16 19:03:25.110821625 -0400
172 @@ -2670,3 +2670,12 @@ PyMethod_Fini(void)
174 (void)PyMethod_ClearFreeList();
177 +/* Print summary info about the state of the optimized allocator */
179 +_PyMethod_DebugMallocStats(FILE *out)
181 + _PyDebugAllocatorStats(out,
182 + "free PyMethodObject",
183 + numfree, sizeof(PyMethodObject));
185 diff -up Python-2.7.2/Objects/dictobject.c.add-debug-malloc-stats Python-2.7.2/Objects/dictobject.c
186 --- Python-2.7.2/Objects/dictobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
187 +++ Python-2.7.2/Objects/dictobject.c 2011-09-16 19:03:25.111821625 -0400
188 @@ -225,6 +225,15 @@ show_track(void)
189 static PyDictObject *free_list[PyDict_MAXFREELIST];
190 static int numfree = 0;
192 +/* Print summary info about the state of the optimized allocator */
194 +_PyDict_DebugMallocStats(FILE *out)
196 + _PyDebugAllocatorStats(out,
197 + "free PyDictObject", numfree, sizeof(PyDictObject));
204 diff -up Python-2.7.2/Objects/floatobject.c.add-debug-malloc-stats Python-2.7.2/Objects/floatobject.c
205 --- Python-2.7.2/Objects/floatobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
206 +++ Python-2.7.2/Objects/floatobject.c 2011-09-16 19:03:25.111821625 -0400
207 @@ -35,6 +35,22 @@ typedef struct _floatblock PyFloatBlock;
208 static PyFloatBlock *block_list = NULL;
209 static PyFloatObject *free_list = NULL;
211 +/* Print summary info about the state of the optimized allocator */
213 +_PyFloat_DebugMallocStats(FILE *out)
215 + int num_blocks = 0;
216 + PyFloatBlock *block;
218 + /* Walk the block list, counting */
219 + for (block = block_list; block ; block = block->next) {
223 + _PyDebugAllocatorStats(out,
224 + "PyFloatBlock", num_blocks, sizeof(PyFloatBlock));
227 static PyFloatObject *
230 diff -up Python-2.7.2/Objects/frameobject.c.add-debug-malloc-stats Python-2.7.2/Objects/frameobject.c
231 --- Python-2.7.2/Objects/frameobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
232 +++ Python-2.7.2/Objects/frameobject.c 2011-09-16 19:03:25.112821625 -0400
233 @@ -980,3 +980,13 @@ PyFrame_Fini(void)
234 Py_XDECREF(builtin_object);
235 builtin_object = NULL;
238 +/* Print summary info about the state of the optimized allocator */
240 +_PyFrame_DebugMallocStats(FILE *out)
242 + _PyDebugAllocatorStats(out,
243 + "free PyFrameObject",
244 + numfree, sizeof(PyFrameObject));
247 diff -up Python-2.7.2/Objects/intobject.c.add-debug-malloc-stats Python-2.7.2/Objects/intobject.c
248 --- Python-2.7.2/Objects/intobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
249 +++ Python-2.7.2/Objects/intobject.c 2011-09-16 19:03:25.112821625 -0400
250 @@ -44,6 +44,23 @@ typedef struct _intblock PyIntBlock;
251 static PyIntBlock *block_list = NULL;
252 static PyIntObject *free_list = NULL;
255 +/* Print summary info about the state of the optimized allocator */
257 +_PyInt_DebugMallocStats(FILE *out)
259 + int num_blocks = 0;
262 + /* Walk the block list, counting */
263 + for (block = block_list; block ; block = block->next) {
267 + _PyDebugAllocatorStats(out,
268 + "PyIntBlock", num_blocks, sizeof(PyIntBlock));
274 diff -up Python-2.7.2/Objects/listobject.c.add-debug-malloc-stats Python-2.7.2/Objects/listobject.c
275 --- Python-2.7.2/Objects/listobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
276 +++ Python-2.7.2/Objects/listobject.c 2011-09-16 19:03:25.113821625 -0400
277 @@ -109,6 +109,15 @@ PyList_Fini(void)
281 +/* Print summary info about the state of the optimized allocator */
283 +_PyList_DebugMallocStats(FILE *out)
285 + _PyDebugAllocatorStats(out,
286 + "free PyListObject",
287 + numfree, sizeof(PyListObject));
291 PyList_New(Py_ssize_t size)
293 diff -up Python-2.7.2/Objects/methodobject.c.add-debug-malloc-stats Python-2.7.2/Objects/methodobject.c
294 --- Python-2.7.2/Objects/methodobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
295 +++ Python-2.7.2/Objects/methodobject.c 2011-09-16 19:03:25.113821625 -0400
296 @@ -412,6 +412,15 @@ PyCFunction_Fini(void)
297 (void)PyCFunction_ClearFreeList();
300 +/* Print summary info about the state of the optimized allocator */
302 +_PyCFunction_DebugMallocStats(FILE *out)
304 + _PyDebugAllocatorStats(out,
305 + "free PyCFunction",
306 + numfree, sizeof(PyCFunction));
309 /* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
310 but it's part of the API so we need to keep a function around that
311 existing C extensions can call.
312 diff -up Python-2.7.2/Objects/object.c.add-debug-malloc-stats Python-2.7.2/Objects/object.c
313 --- Python-2.7.2/Objects/object.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
314 +++ Python-2.7.2/Objects/object.c 2011-09-16 19:04:46.463820849 -0400
315 @@ -2334,6 +2334,23 @@ PyMem_Free(void *p)
320 +_PyObject_DebugTypeStats(FILE *out)
322 + _PyString_DebugMallocStats(out);
323 + _PyCFunction_DebugMallocStats(out);
324 + _PyDict_DebugMallocStats(out);
325 + _PyFloat_DebugMallocStats(out);
326 + _PyFrame_DebugMallocStats(out);
327 + _PyInt_DebugMallocStats(out);
328 + _PyList_DebugMallocStats(out);
329 + _PyMethod_DebugMallocStats(out);
330 + _PySet_DebugMallocStats(out);
331 + _PyTuple_DebugMallocStats(out);
332 +#if Py_USING_UNICODE
333 + _PyUnicode_DebugMallocStats(out);
337 /* These methods are used to control infinite recursion in repr, str, print,
338 etc. Container objects that may recursively contain themselves,
339 diff -up Python-2.7.2/Objects/obmalloc.c.add-debug-malloc-stats Python-2.7.2/Objects/obmalloc.c
340 --- Python-2.7.2/Objects/obmalloc.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
341 +++ Python-2.7.2/Objects/obmalloc.c 2011-09-16 19:03:25.114821625 -0400
342 @@ -508,12 +508,10 @@ static struct arena_object* usable_arena
343 /* Number of arenas allocated that haven't been free()'d. */
344 static size_t narenas_currently_allocated = 0;
346 -#ifdef PYMALLOC_DEBUG
347 /* Total number of times malloc() called to allocate an arena. */
348 static size_t ntimes_arena_allocated = 0;
349 /* High water mark (max value ever seen) for narenas_currently_allocated. */
350 static size_t narenas_highwater = 0;
353 /* Allocate a new arena. If we run out of memory, return NULL. Else
354 * allocate a new arena, and return the address of an arena_object
355 @@ -528,7 +526,7 @@ new_arena(void)
357 #ifdef PYMALLOC_DEBUG
358 if (Py_GETENV("PYTHONMALLOCSTATS"))
359 - _PyObject_DebugMallocStats();
360 + _PyObject_DebugMallocStats(stderr);
362 if (unused_arena_objects == NULL) {
364 @@ -588,11 +586,9 @@ new_arena(void)
365 arenaobj->address = (uptr)address;
367 ++narenas_currently_allocated;
368 -#ifdef PYMALLOC_DEBUG
369 ++ntimes_arena_allocated;
370 if (narenas_currently_allocated > narenas_highwater)
371 narenas_highwater = narenas_currently_allocated;
373 arenaobj->freepools = NULL;
374 /* pool_address <- first pool-aligned address in the arena
375 nfreepools <- number of whole pools that fit after alignment */
376 @@ -1694,17 +1690,19 @@ _PyObject_DebugDumpAddress(const void *p
380 +#endif /* PYMALLOC_DEBUG */
383 -printone(const char* msg, size_t value)
384 +printone(FILE *out, const char* msg, size_t value)
388 size_t origvalue = value;
390 - fputs(msg, stderr);
392 for (i = (int)strlen(msg); i < 35; ++i)
393 - fputc(' ', stderr);
394 - fputc('=', stderr);
398 /* Write the value with commas. */
400 @@ -1725,17 +1723,32 @@ printone(const char* msg, size_t value)
404 - fputs(buf, stderr);
410 -/* Print summary info to stderr about the state of pymalloc's structures.
412 +_PyDebugAllocatorStats(FILE *out,
413 + const char *block_name, int num_blocks, size_t sizeof_block)
417 + PyOS_snprintf(buf1, sizeof(buf1),
418 + "%d %ss * %zd bytes each",
419 + num_blocks, block_name, sizeof_block);
420 + PyOS_snprintf(buf2, sizeof(buf2),
422 + (void)printone(out, buf2, num_blocks * sizeof_block);
426 +/* Print summary info to "out" about the state of pymalloc's structures.
427 * In Py_DEBUG mode, also perform some expensive internal consistency
431 -_PyObject_DebugMallocStats(void)
432 +_PyObject_DebugMallocStats(FILE *out)
435 const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
436 @@ -1764,7 +1777,7 @@ _PyObject_DebugMallocStats(void)
440 - fprintf(stderr, "Small block threshold = %d, in %u size classes.\n",
441 + fprintf(out, "Small block threshold = %d, in %u size classes.\n",
442 SMALL_REQUEST_THRESHOLD, numclasses);
444 for (i = 0; i < numclasses; ++i)
445 @@ -1818,10 +1831,10 @@ _PyObject_DebugMallocStats(void)
447 assert(narenas == narenas_currently_allocated);
449 - fputc('\n', stderr);
451 fputs("class size num pools blocks in use avail blocks\n"
452 "----- ---- --------- ------------- ------------\n",
456 for (i = 0; i < numclasses; ++i) {
457 size_t p = numpools[i];
458 @@ -1832,7 +1845,7 @@ _PyObject_DebugMallocStats(void)
459 assert(b == 0 && f == 0);
462 - fprintf(stderr, "%5u %6u "
463 + fprintf(out, "%5u %6u "
464 "%11" PY_FORMAT_SIZE_T "u "
465 "%15" PY_FORMAT_SIZE_T "u "
466 "%13" PY_FORMAT_SIZE_T "u\n",
467 @@ -1842,36 +1855,35 @@ _PyObject_DebugMallocStats(void)
468 pool_header_bytes += p * POOL_OVERHEAD;
469 quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size);
471 - fputc('\n', stderr);
472 - (void)printone("# times object malloc called", serialno);
474 - (void)printone("# arenas allocated total", ntimes_arena_allocated);
475 - (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas);
476 - (void)printone("# arenas highwater mark", narenas_highwater);
477 - (void)printone("# arenas allocated current", narenas);
479 +#ifdef PYMALLOC_DEBUG
480 + (void)printone(out, "# times object malloc called", serialno);
482 + (void)printone(out, "# arenas allocated total", ntimes_arena_allocated);
483 + (void)printone(out, "# arenas reclaimed", ntimes_arena_allocated - narenas);
484 + (void)printone(out, "# arenas highwater mark", narenas_highwater);
485 + (void)printone(out, "# arenas allocated current", narenas);
487 PyOS_snprintf(buf, sizeof(buf),
488 "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena",
489 narenas, ARENA_SIZE);
490 - (void)printone(buf, narenas * ARENA_SIZE);
491 + (void)printone(out, buf, narenas * ARENA_SIZE);
493 - fputc('\n', stderr);
496 - total = printone("# bytes in allocated blocks", allocated_bytes);
497 - total += printone("# bytes in available blocks", available_bytes);
498 + total = printone(out, "# bytes in allocated blocks", allocated_bytes);
499 + total += printone(out, "# bytes in available blocks", available_bytes);
501 PyOS_snprintf(buf, sizeof(buf),
502 "%u unused pools * %d bytes", numfreepools, POOL_SIZE);
503 - total += printone(buf, (size_t)numfreepools * POOL_SIZE);
504 + total += printone(out, buf, (size_t)numfreepools * POOL_SIZE);
506 - total += printone("# bytes lost to pool headers", pool_header_bytes);
507 - total += printone("# bytes lost to quantization", quantization);
508 - total += printone("# bytes lost to arena alignment", arena_alignment);
509 - (void)printone("Total", total);
510 + total += printone(out, "# bytes lost to pool headers", pool_header_bytes);
511 + total += printone(out, "# bytes lost to quantization", quantization);
512 + total += printone(out, "# bytes lost to arena alignment", arena_alignment);
513 + (void)printone(out, "Total", total);
516 -#endif /* PYMALLOC_DEBUG */
518 #ifdef Py_USING_MEMORY_DEBUGGER
519 /* Make this function last so gcc won't inline it since the definition is
520 * after the reference.
521 diff -up Python-2.7.2/Objects/setobject.c.add-debug-malloc-stats Python-2.7.2/Objects/setobject.c
522 --- Python-2.7.2/Objects/setobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
523 +++ Python-2.7.2/Objects/setobject.c 2011-09-16 19:03:25.115821625 -0400
524 @@ -1088,6 +1088,16 @@ PySet_Fini(void)
525 Py_CLEAR(emptyfrozenset);
528 +/* Print summary info about the state of the optimized allocator */
530 +_PySet_DebugMallocStats(FILE *out)
532 + _PyDebugAllocatorStats(out,
533 + "free PySetObject",
534 + numfree, sizeof(PySetObject));
539 set_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
541 diff -up Python-2.7.2/Objects/stringobject.c.add-debug-malloc-stats Python-2.7.2/Objects/stringobject.c
542 --- Python-2.7.2/Objects/stringobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
543 +++ Python-2.7.2/Objects/stringobject.c 2011-09-16 19:03:25.116821625 -0400
544 @@ -4822,3 +4822,43 @@ void _Py_ReleaseInternedStrings(void)
545 PyDict_Clear(interned);
549 +void _PyString_DebugMallocStats(FILE *out)
552 + int num_immortal = 0, num_mortal = 0;
553 + ssize_t immortal_size = 0, mortal_size = 0;
555 + if (interned == NULL || !PyDict_Check(interned))
558 + for (i = 0; i <= ((PyDictObject*)interned)->ma_mask; i++) {
559 + PyDictEntry *ep = ((PyDictObject*)interned)->ma_table + i;
560 + PyObject *pvalue = ep->me_value;
561 + if (pvalue != NULL) {
562 + PyStringObject *s = (PyStringObject *)ep->me_key;
564 + switch (s->ob_sstate) {
565 + case SSTATE_NOT_INTERNED:
566 + /* XXX Shouldn't happen */
568 + case SSTATE_INTERNED_IMMORTAL:
570 + immortal_size += s->ob_size;
572 + case SSTATE_INTERNED_MORTAL:
574 + mortal_size += s->ob_size;
577 + Py_FatalError("Inconsistent interned string state.");
582 + fprintf(out, "%d mortal interned strings\n", num_mortal);
583 + fprintf(out, "%d immortal interned strings\n", num_immortal);
584 + fprintf(out, "total size of all interned strings: "
586 + "mortal/immortal\n", mortal_size, immortal_size);
588 diff -up Python-2.7.2/Objects/tupleobject.c.add-debug-malloc-stats Python-2.7.2/Objects/tupleobject.c
589 --- Python-2.7.2/Objects/tupleobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
590 +++ Python-2.7.2/Objects/tupleobject.c 2011-09-16 19:03:25.116821625 -0400
591 @@ -44,6 +44,22 @@ show_track(void)
595 +/* Print summary info about the state of the optimized allocator */
597 +_PyTuple_DebugMallocStats(FILE *out)
599 +#if PyTuple_MAXSAVESIZE > 0
602 + for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
603 + PyOS_snprintf(buf, sizeof(buf),
604 + "free %d-sized PyTupleObject", i);
605 + _PyDebugAllocatorStats(out,
607 + numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i));
613 PyTuple_New(register Py_ssize_t size)
614 diff -up Python-2.7.2/Objects/unicodeobject.c.add-debug-malloc-stats Python-2.7.2/Objects/unicodeobject.c
615 --- Python-2.7.2/Objects/unicodeobject.c.add-debug-malloc-stats 2011-06-11 11:46:27.000000000 -0400
616 +++ Python-2.7.2/Objects/unicodeobject.c 2011-09-16 19:03:25.118821625 -0400
617 @@ -8883,6 +8883,12 @@ _PyUnicode_Fini(void)
618 (void)PyUnicode_ClearFreeList();
621 +void _PyUnicode_DebugMallocStats(FILE *out)
623 + _PyDebugAllocatorStats(out, "free PyUnicodeObject", numfree,
624 + sizeof(PyUnicodeObject));
630 diff -up Python-2.7.2/Python/pythonrun.c.add-debug-malloc-stats Python-2.7.2/Python/pythonrun.c
631 --- Python-2.7.2/Python/pythonrun.c.add-debug-malloc-stats 2011-09-16 19:03:25.025821626 -0400
632 +++ Python-2.7.2/Python/pythonrun.c 2011-09-16 19:03:25.118821625 -0400
633 @@ -549,7 +549,7 @@ Py_Finalize(void)
634 #endif /* Py_TRACE_REFS */
635 #ifdef PYMALLOC_DEBUG
636 if (Py_GETENV("PYTHONMALLOCSTATS"))
637 - _PyObject_DebugMallocStats();
638 + _PyObject_DebugMallocStats(stderr);
642 diff -up Python-2.7.2/Python/sysmodule.c.add-debug-malloc-stats Python-2.7.2/Python/sysmodule.c
643 --- Python-2.7.2/Python/sysmodule.c.add-debug-malloc-stats 2011-09-16 19:03:25.007821626 -0400
644 +++ Python-2.7.2/Python/sysmodule.c 2011-09-16 19:03:25.119821625 -0400
645 @@ -872,6 +872,57 @@ a 11-tuple where the entries in the tupl
650 +sys_debugmallocstats(PyObject *self, PyObject *args)
652 + PyObject *file = NULL;
655 + if (!PyArg_ParseTuple(args, "|O!",
656 + &PyFile_Type, &file)) {
660 + /* Default to sys.stderr: */
661 + file = PySys_GetObject("stderr");
663 + PyErr_SetString(PyExc_ValueError, "sys.stderr not set");
666 + if (!PyFile_Check(file)) {
667 + PyErr_SetString(PyExc_TypeError, "sys.stderr is not a file");
673 + /* OK, we now own a ref on non-NULL "file" */
675 + fp = PyFile_AsFile(file);
677 + PyErr_SetString(PyExc_ValueError, "file is closed");
682 + _PyObject_DebugMallocStats(fp);
684 + _PyObject_DebugTypeStats(fp);
690 +PyDoc_STRVAR(debugmallocstats_doc,
691 +"_debugmallocstats([file])\n\
693 +Print summary info to the given file (or sys.stderr) about the state of\n\
694 +pymalloc's structures.\n\
696 +In Py_DEBUG mode, also perform some expensive internal consistency\n\
701 /* Defined in objects.c because it uses static globals if that file */
702 extern PyObject *_Py_GetObjects(PyObject *, PyObject *);
703 @@ -970,6 +1021,8 @@ static PyMethodDef sys_methods[] = {
704 {"settrace", sys_settrace, METH_O, settrace_doc},
705 {"gettrace", sys_gettrace, METH_NOARGS, gettrace_doc},
706 {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
707 + {"_debugmallocstats", sys_debugmallocstats, METH_VARARGS,
708 + debugmallocstats_doc},
709 {NULL, NULL} /* sentinel */