From ab415c6cddafcf5b295bf4433c2142a84c0f8e64 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 16 Sep 2011 19:28:20 -0400 Subject: [PATCH] add a sys._debugmallocstats() function (patch 147) * Fri Sep 16 2011 David Malcolm - 3.2.2-6 - add a sys._debugmallocstats() function (patch 147) --- 00147-add-debug-malloc-stats.patch | 590 +++++++++++++++++++++++++++++ python3.spec | 11 +- 2 files changed, 600 insertions(+), 1 deletion(-) create mode 100644 00147-add-debug-malloc-stats.patch diff --git a/00147-add-debug-malloc-stats.patch b/00147-add-debug-malloc-stats.patch new file mode 100644 index 0000000..e2a8342 --- /dev/null +++ b/00147-add-debug-malloc-stats.patch @@ -0,0 +1,590 @@ +diff -up Python-3.2.2/Include/dictobject.h.add-debug-malloc-stats Python-3.2.2/Include/dictobject.h +--- Python-3.2.2/Include/dictobject.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/dictobject.h 2011-09-16 18:57:24.969825060 -0400 +@@ -156,6 +156,8 @@ PyAPI_FUNC(PyObject *) PyDict_GetItemStr + PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item); + PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key); + ++PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out); ++ + #ifdef __cplusplus + } + #endif +diff -up Python-3.2.2/Include/floatobject.h.add-debug-malloc-stats Python-3.2.2/Include/floatobject.h +--- Python-3.2.2/Include/floatobject.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/floatobject.h 2011-09-16 18:57:24.970825060 -0400 +@@ -110,6 +110,8 @@ PyAPI_FUNC(double) _PyFloat_Unpack8(cons + /* free list api */ + PyAPI_FUNC(int) PyFloat_ClearFreeList(void); + ++PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out); ++ + /* Format the object based on the format_spec, as defined in PEP 3101 + (Advanced String Formatting). */ + PyAPI_FUNC(PyObject *) _PyFloat_FormatAdvanced(PyObject *obj, +diff -up Python-3.2.2/Include/frameobject.h.add-debug-malloc-stats Python-3.2.2/Include/frameobject.h +--- Python-3.2.2/Include/frameobject.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/frameobject.h 2011-09-16 18:57:24.970825060 -0400 +@@ -79,6 +79,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(Py + + PyAPI_FUNC(int) PyFrame_ClearFreeList(void); + ++PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out); ++ + /* Return the line of code the frame is currently executing. */ + PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); + +diff -up Python-3.2.2/Include/listobject.h.add-debug-malloc-stats Python-3.2.2/Include/listobject.h +--- Python-3.2.2/Include/listobject.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/listobject.h 2011-09-16 18:57:24.971825060 -0400 +@@ -71,6 +71,8 @@ PyAPI_FUNC(PyObject *) _PyList_Extend(Py + #define PyList_GET_SIZE(op) Py_SIZE(op) + #endif + ++PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out); ++ + #ifdef __cplusplus + } + #endif +diff -up Python-3.2.2/Include/methodobject.h.add-debug-malloc-stats Python-3.2.2/Include/methodobject.h +--- Python-3.2.2/Include/methodobject.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/methodobject.h 2011-09-16 18:57:24.971825060 -0400 +@@ -81,6 +81,10 @@ typedef struct { + + PyAPI_FUNC(int) PyCFunction_ClearFreeList(void); + ++PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out); ++PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out); ++ ++ + #ifdef __cplusplus + } + #endif +diff -up Python-3.2.2/Include/object.h.add-debug-malloc-stats Python-3.2.2/Include/object.h +--- Python-3.2.2/Include/object.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/object.h 2011-09-16 18:57:24.972825060 -0400 +@@ -919,6 +919,13 @@ PyAPI_DATA(PyObject *) _PyTrash_delete_l + else \ + _PyTrash_deposit_object((PyObject*)op); + ++PyAPI_FUNC(void) ++_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks, ++ size_t sizeof_block); ++ ++PyAPI_FUNC(void) ++_PyObject_DebugTypeStats(FILE *out); ++ + #ifdef __cplusplus + } + #endif +diff -up Python-3.2.2/Include/objimpl.h.add-debug-malloc-stats Python-3.2.2/Include/objimpl.h +--- Python-3.2.2/Include/objimpl.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/objimpl.h 2011-09-16 18:57:24.972825060 -0400 +@@ -101,13 +101,13 @@ PyAPI_FUNC(void) PyObject_Free(void *); + + /* Macros */ + #ifdef WITH_PYMALLOC ++PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out); + #ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */ + PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes); + PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes); + PyAPI_FUNC(void) _PyObject_DebugFree(void *p); + PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p); + PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p); +-PyAPI_FUNC(void) _PyObject_DebugMallocStats(void); + PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes); + PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes); + PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p); +diff -up Python-3.2.2/Include/setobject.h.add-debug-malloc-stats Python-3.2.2/Include/setobject.h +--- Python-3.2.2/Include/setobject.h.add-debug-malloc-stats 2011-09-16 19:10:58.448817301 -0400 ++++ Python-3.2.2/Include/setobject.h 2011-09-16 19:12:16.343816559 -0400 +@@ -101,6 +101,8 @@ PyAPI_FUNC(PyObject *) PySet_Pop(PyObjec + PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); + #endif + ++PyAPI_FUNC(void) _PySet_DebugMallocStats(FILE *out); ++ + #ifdef __cplusplus + } + #endif +diff -up Python-3.2.2/Include/tupleobject.h.add-debug-malloc-stats Python-3.2.2/Include/tupleobject.h +--- Python-3.2.2/Include/tupleobject.h.add-debug-malloc-stats 2011-09-16 19:10:45.540817425 -0400 ++++ Python-3.2.2/Include/tupleobject.h 2011-09-16 19:12:41.446816320 -0400 +@@ -63,6 +63,7 @@ PyAPI_FUNC(void) _PyTuple_MaybeUntrack(P + #endif + + PyAPI_FUNC(int) PyTuple_ClearFreeList(void); ++PyAPI_FUNC(void) _PyTuple_DebugMallocStats(FILE *out); + + #ifdef __cplusplus + } +diff -up Python-3.2.2/Include/unicodeobject.h.add-debug-malloc-stats Python-3.2.2/Include/unicodeobject.h +--- Python-3.2.2/Include/unicodeobject.h.add-debug-malloc-stats 2011-09-03 12:16:40.000000000 -0400 ++++ Python-3.2.2/Include/unicodeobject.h 2011-09-16 18:57:24.973825060 -0400 +@@ -1670,6 +1670,8 @@ PyAPI_FUNC(Py_UNICODE*) PyUnicode_AsUnic + ); + #endif /* Py_LIMITED_API */ + ++PyAPI_FUNC(void) _PyUnicode_DebugMallocStats(FILE *out); ++ + #ifdef __cplusplus + } + #endif +diff -up Python-3.2.2/Lib/test/test_sys.py.add-debug-malloc-stats Python-3.2.2/Lib/test/test_sys.py +--- Python-3.2.2/Lib/test/test_sys.py.add-debug-malloc-stats 2011-09-16 18:57:24.940825060 -0400 ++++ Python-3.2.2/Lib/test/test_sys.py 2011-09-16 19:23:50.415809940 -0400 +@@ -564,6 +564,18 @@ class SysModuleTest(unittest.TestCase): + expected = None + self.check_fsencoding(fs_encoding, expected) + ++ def test_debugmallocstats(self): ++ # Test sys._debugmallocstats() ++ ++ import subprocess ++ ++ # Verify writing to stderr: ++ p = subprocess.Popen([sys.executable, ++ '-c', 'import sys; sys._debugmallocstats()'], ++ stderr=subprocess.PIPE) ++ out, err = p.communicate() ++ p.wait() ++ self.assertIn(b"arenas allocated current", err) + + class SizeofTest(unittest.TestCase): + +diff -up Python-3.2.2/Objects/classobject.c.add-debug-malloc-stats Python-3.2.2/Objects/classobject.c +--- Python-3.2.2/Objects/classobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/classobject.c 2011-09-16 18:57:24.975825060 -0400 +@@ -399,6 +399,15 @@ PyMethod_Fini(void) + (void)PyMethod_ClearFreeList(); + } + ++/* Print summary info about the state of the optimized allocator */ ++void ++_PyMethod_DebugMallocStats(FILE *out) ++{ ++ _PyDebugAllocatorStats(out, ++ "free PyMethodObject", ++ numfree, sizeof(PyMethodObject)); ++} ++ + /* ------------------------------------------------------------------------ + * instance method + */ +diff -up Python-3.2.2/Objects/dictobject.c.add-debug-malloc-stats Python-3.2.2/Objects/dictobject.c +--- Python-3.2.2/Objects/dictobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/dictobject.c 2011-09-16 18:57:24.976825060 -0400 +@@ -217,6 +217,15 @@ show_track(void) + static PyDictObject *free_list[PyDict_MAXFREELIST]; + static int numfree = 0; + ++/* Print summary info about the state of the optimized allocator */ ++void ++_PyDict_DebugMallocStats(FILE *out) ++{ ++ _PyDebugAllocatorStats(out, ++ "free PyDictObject", numfree, sizeof(PyDictObject)); ++} ++ ++ + void + PyDict_Fini(void) + { +diff -up Python-3.2.2/Objects/floatobject.c.add-debug-malloc-stats Python-3.2.2/Objects/floatobject.c +--- Python-3.2.2/Objects/floatobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/floatobject.c 2011-09-16 18:57:24.981825060 -0400 +@@ -50,6 +50,22 @@ typedef struct _floatblock PyFloatBlock; + static PyFloatBlock *block_list = NULL; + static PyFloatObject *free_list = NULL; + ++/* Print summary info about the state of the optimized allocator */ ++void ++_PyFloat_DebugMallocStats(FILE *out) ++{ ++ int num_blocks = 0; ++ PyFloatBlock *block; ++ ++ /* Walk the block list, counting */ ++ for (block = block_list; block ; block = block->next) { ++ num_blocks++; ++ } ++ ++ _PyDebugAllocatorStats(out, ++ "PyFloatBlock", num_blocks, sizeof(PyFloatBlock)); ++} ++ + static PyFloatObject * + fill_free_list(void) + { +diff -up Python-3.2.2/Objects/frameobject.c.add-debug-malloc-stats Python-3.2.2/Objects/frameobject.c +--- Python-3.2.2/Objects/frameobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/frameobject.c 2011-09-16 18:57:24.982825060 -0400 +@@ -953,3 +953,13 @@ PyFrame_Fini(void) + Py_XDECREF(builtin_object); + builtin_object = NULL; + } ++ ++/* Print summary info about the state of the optimized allocator */ ++void ++_PyFrame_DebugMallocStats(FILE *out) ++{ ++ _PyDebugAllocatorStats(out, ++ "free PyFrameObject", ++ numfree, sizeof(PyFrameObject)); ++} ++ +diff -up Python-3.2.2/Objects/listobject.c.add-debug-malloc-stats Python-3.2.2/Objects/listobject.c +--- Python-3.2.2/Objects/listobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/listobject.c 2011-09-16 18:57:24.983825060 -0400 +@@ -109,6 +109,15 @@ PyList_Fini(void) + } + } + ++/* Print summary info about the state of the optimized allocator */ ++void ++_PyList_DebugMallocStats(FILE *out) ++{ ++ _PyDebugAllocatorStats(out, ++ "free PyListObject", ++ numfree, sizeof(PyListObject)); ++} ++ + PyObject * + PyList_New(Py_ssize_t size) + { +diff -up Python-3.2.2/Objects/methodobject.c.add-debug-malloc-stats Python-3.2.2/Objects/methodobject.c +--- Python-3.2.2/Objects/methodobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/methodobject.c 2011-09-16 18:57:24.983825060 -0400 +@@ -303,6 +303,15 @@ PyCFunction_Fini(void) + (void)PyCFunction_ClearFreeList(); + } + ++/* Print summary info about the state of the optimized allocator */ ++void ++_PyCFunction_DebugMallocStats(FILE *out) ++{ ++ _PyDebugAllocatorStats(out, ++ "free PyCFunction", ++ numfree, sizeof(PyCFunction)); ++} ++ + /* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(), + but it's part of the API so we need to keep a function around that + existing C extensions can call. +diff -up Python-3.2.2/Objects/object.c.add-debug-malloc-stats Python-3.2.2/Objects/object.c +--- Python-3.2.2/Objects/object.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/object.c 2011-09-16 19:04:20.351821098 -0400 +@@ -1781,6 +1781,19 @@ PyMem_Free(void *p) + PyMem_FREE(p); + } + ++void ++_PyObject_DebugTypeStats(FILE *out) ++{ ++ _PyCFunction_DebugMallocStats(out); ++ _PyDict_DebugMallocStats(out); ++ _PyFloat_DebugMallocStats(out); ++ _PyFrame_DebugMallocStats(out); ++ _PyList_DebugMallocStats(out); ++ _PyMethod_DebugMallocStats(out); ++ _PySet_DebugMallocStats(out); ++ _PyTuple_DebugMallocStats(out); ++ _PyUnicode_DebugMallocStats(out); ++} + + /* These methods are used to control infinite recursion in repr, str, print, + etc. Container objects that may recursively contain themselves, +diff -up Python-3.2.2/Objects/obmalloc.c.add-debug-malloc-stats Python-3.2.2/Objects/obmalloc.c +--- Python-3.2.2/Objects/obmalloc.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/obmalloc.c 2011-09-16 18:57:24.985825060 -0400 +@@ -508,12 +508,10 @@ static struct arena_object* usable_arena + /* Number of arenas allocated that haven't been free()'d. */ + static size_t narenas_currently_allocated = 0; + +-#ifdef PYMALLOC_DEBUG + /* Total number of times malloc() called to allocate an arena. */ + static size_t ntimes_arena_allocated = 0; + /* High water mark (max value ever seen) for narenas_currently_allocated. */ + static size_t narenas_highwater = 0; +-#endif + + /* Allocate a new arena. If we run out of memory, return NULL. Else + * allocate a new arena, and return the address of an arena_object +@@ -528,7 +526,7 @@ new_arena(void) + + #ifdef PYMALLOC_DEBUG + if (Py_GETENV("PYTHONMALLOCSTATS")) +- _PyObject_DebugMallocStats(); ++ _PyObject_DebugMallocStats(stderr); + #endif + if (unused_arena_objects == NULL) { + uint i; +@@ -588,11 +586,9 @@ new_arena(void) + } + + ++narenas_currently_allocated; +-#ifdef PYMALLOC_DEBUG + ++ntimes_arena_allocated; + if (narenas_currently_allocated > narenas_highwater) + narenas_highwater = narenas_currently_allocated; +-#endif + arenaobj->freepools = NULL; + /* pool_address <- first pool-aligned address in the arena + nfreepools <- number of whole pools that fit after alignment */ +@@ -1694,17 +1690,19 @@ _PyObject_DebugDumpAddress(const void *p + } + } + ++#endif /* PYMALLOC_DEBUG */ ++ + static size_t +-printone(const char* msg, size_t value) ++printone(FILE *out, const char* msg, size_t value) + { + int i, k; + char buf[100]; + size_t origvalue = value; + +- fputs(msg, stderr); ++ fputs(msg, out); + for (i = (int)strlen(msg); i < 35; ++i) +- fputc(' ', stderr); +- fputc('=', stderr); ++ fputc(' ', out); ++ fputc('=', out); + + /* Write the value with commas. */ + i = 22; +@@ -1725,17 +1723,32 @@ printone(const char* msg, size_t value) + + while (i >= 0) + buf[i--] = ' '; +- fputs(buf, stderr); ++ fputs(buf, out); + + return origvalue; + } + +-/* Print summary info to stderr about the state of pymalloc's structures. ++void ++_PyDebugAllocatorStats(FILE *out, ++ const char *block_name, int num_blocks, size_t sizeof_block) ++{ ++ char buf1[128]; ++ char buf2[128]; ++ PyOS_snprintf(buf1, sizeof(buf1), ++ "%d %ss * %zd bytes each", ++ num_blocks, block_name, sizeof_block); ++ PyOS_snprintf(buf2, sizeof(buf2), ++ "%48s ", buf1); ++ (void)printone(out, buf2, num_blocks * sizeof_block); ++} ++ ++ ++/* Print summary info to "out" about the state of pymalloc's structures. + * In Py_DEBUG mode, also perform some expensive internal consistency + * checks. + */ + void +-_PyObject_DebugMallocStats(void) ++_PyObject_DebugMallocStats(FILE *out) + { + uint i; + const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT; +@@ -1764,7 +1777,7 @@ _PyObject_DebugMallocStats(void) + size_t total; + char buf[128]; + +- fprintf(stderr, "Small block threshold = %d, in %u size classes.\n", ++ fprintf(out, "Small block threshold = %d, in %u size classes.\n", + SMALL_REQUEST_THRESHOLD, numclasses); + + for (i = 0; i < numclasses; ++i) +@@ -1820,10 +1833,10 @@ _PyObject_DebugMallocStats(void) + } + assert(narenas == narenas_currently_allocated); + +- fputc('\n', stderr); ++ fputc('\n', out); + fputs("class size num pools blocks in use avail blocks\n" + "----- ---- --------- ------------- ------------\n", +- stderr); ++ out); + + for (i = 0; i < numclasses; ++i) { + size_t p = numpools[i]; +@@ -1834,7 +1847,7 @@ _PyObject_DebugMallocStats(void) + assert(b == 0 && f == 0); + continue; + } +- fprintf(stderr, "%5u %6u " ++ fprintf(out, "%5u %6u " + "%11" PY_FORMAT_SIZE_T "u " + "%15" PY_FORMAT_SIZE_T "u " + "%13" PY_FORMAT_SIZE_T "u\n", +@@ -1844,36 +1857,35 @@ _PyObject_DebugMallocStats(void) + pool_header_bytes += p * POOL_OVERHEAD; + quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size); + } +- fputc('\n', stderr); +- (void)printone("# times object malloc called", serialno); +- +- (void)printone("# arenas allocated total", ntimes_arena_allocated); +- (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas); +- (void)printone("# arenas highwater mark", narenas_highwater); +- (void)printone("# arenas allocated current", narenas); ++ fputc('\n', out); ++#ifdef PYMALLOC_DEBUG ++ (void)printone(out, "# times object malloc called", serialno); ++#endif ++ (void)printone(out, "# arenas allocated total", ntimes_arena_allocated); ++ (void)printone(out, "# arenas reclaimed", ntimes_arena_allocated - narenas); ++ (void)printone(out, "# arenas highwater mark", narenas_highwater); ++ (void)printone(out, "# arenas allocated current", narenas); + + PyOS_snprintf(buf, sizeof(buf), + "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena", + narenas, ARENA_SIZE); +- (void)printone(buf, narenas * ARENA_SIZE); ++ (void)printone(out, buf, narenas * ARENA_SIZE); + +- fputc('\n', stderr); ++ fputc('\n', out); + +- total = printone("# bytes in allocated blocks", allocated_bytes); +- total += printone("# bytes in available blocks", available_bytes); ++ total = printone(out, "# bytes in allocated blocks", allocated_bytes); ++ total += printone(out, "# bytes in available blocks", available_bytes); + + PyOS_snprintf(buf, sizeof(buf), + "%u unused pools * %d bytes", numfreepools, POOL_SIZE); +- total += printone(buf, (size_t)numfreepools * POOL_SIZE); ++ total += printone(out, buf, (size_t)numfreepools * POOL_SIZE); + +- total += printone("# bytes lost to pool headers", pool_header_bytes); +- total += printone("# bytes lost to quantization", quantization); +- total += printone("# bytes lost to arena alignment", arena_alignment); +- (void)printone("Total", total); ++ total += printone(out, "# bytes lost to pool headers", pool_header_bytes); ++ total += printone(out, "# bytes lost to quantization", quantization); ++ total += printone(out, "# bytes lost to arena alignment", arena_alignment); ++ (void)printone(out, "Total", total); + } + +-#endif /* PYMALLOC_DEBUG */ +- + #ifdef Py_USING_MEMORY_DEBUGGER + /* Make this function last so gcc won't inline it since the definition is + * after the reference. +diff -up Python-3.2.2/Objects/setobject.c.add-debug-malloc-stats Python-3.2.2/Objects/setobject.c +--- Python-3.2.2/Objects/setobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/setobject.c 2011-09-16 18:57:24.986825060 -0400 +@@ -1090,6 +1090,16 @@ PySet_Fini(void) + Py_CLEAR(emptyfrozenset); + } + ++/* Print summary info about the state of the optimized allocator */ ++void ++_PySet_DebugMallocStats(FILE *out) ++{ ++ _PyDebugAllocatorStats(out, ++ "free PySetObject", ++ numfree, sizeof(PySetObject)); ++} ++ ++ + static PyObject * + set_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { +diff -up Python-3.2.2/Objects/tupleobject.c.add-debug-malloc-stats Python-3.2.2/Objects/tupleobject.c +--- Python-3.2.2/Objects/tupleobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/tupleobject.c 2011-09-16 18:57:24.987825060 -0400 +@@ -44,6 +44,22 @@ show_track(void) + } + #endif + ++/* Print summary info about the state of the optimized allocator */ ++void ++_PyTuple_DebugMallocStats(FILE *out) ++{ ++#if PyTuple_MAXSAVESIZE > 0 ++ int i; ++ char buf[128]; ++ for (i = 1; i < PyTuple_MAXSAVESIZE; i++) { ++ PyOS_snprintf(buf, sizeof(buf), ++ "free %d-sized PyTupleObject", i); ++ _PyDebugAllocatorStats(out, ++ buf, ++ numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i)); ++ } ++#endif ++} + + PyObject * + PyTuple_New(register Py_ssize_t size) +diff -up Python-3.2.2/Objects/unicodeobject.c.add-debug-malloc-stats Python-3.2.2/Objects/unicodeobject.c +--- Python-3.2.2/Objects/unicodeobject.c.add-debug-malloc-stats 2011-09-03 12:16:47.000000000 -0400 ++++ Python-3.2.2/Objects/unicodeobject.c 2011-09-16 18:57:24.990825060 -0400 +@@ -10063,6 +10063,12 @@ _PyUnicode_Fini(void) + (void)PyUnicode_ClearFreeList(); + } + ++void _PyUnicode_DebugMallocStats(FILE *out) ++{ ++ _PyDebugAllocatorStats(out, "free PyUnicodeObject", numfree, ++ sizeof(PyUnicodeObject)); ++} ++ + void + PyUnicode_InternInPlace(PyObject **p) + { +diff -up Python-3.2.2/Python/pythonrun.c.add-debug-malloc-stats Python-3.2.2/Python/pythonrun.c +--- Python-3.2.2/Python/pythonrun.c.add-debug-malloc-stats 2011-09-16 19:24:44.747809422 -0400 ++++ Python-3.2.2/Python/pythonrun.c 2011-09-16 19:25:00.024809277 -0400 +@@ -547,7 +547,7 @@ Py_Finalize(void) + #endif /* Py_TRACE_REFS */ + #ifdef PYMALLOC_DEBUG + if (Py_GETENV("PYTHONMALLOCSTATS")) +- _PyObject_DebugMallocStats(); ++ _PyObject_DebugMallocStats(stderr); + #endif + + call_ll_exitfuncs(); +diff -up Python-3.2.2/Python/sysmodule.c.add-debug-malloc-stats Python-3.2.2/Python/sysmodule.c +--- Python-3.2.2/Python/sysmodule.c.add-debug-malloc-stats 2011-09-03 12:16:49.000000000 -0400 ++++ Python-3.2.2/Python/sysmodule.c 2011-09-16 19:18:45.806812845 -0400 +@@ -994,6 +994,25 @@ a 11-tuple where the entries in the tupl + extern "C" { + #endif + ++static PyObject * ++sys_debugmallocstats(PyObject *self, PyObject *args) ++{ ++ _PyObject_DebugMallocStats(stderr); ++ fputc('\n', stderr); ++ _PyObject_DebugTypeStats(stderr); ++ ++ Py_RETURN_NONE; ++} ++PyDoc_STRVAR(debugmallocstats_doc, ++"_debugmallocstats([file])\n\ ++\n\ ++Print summary info to stderr about the state of\n\ ++pymalloc's structures.\n\ ++\n\ ++In Py_DEBUG mode, also perform some expensive internal consistency\n\ ++checks.\n\ ++"); ++ + #ifdef Py_TRACE_REFS + /* Defined in objects.c because it uses static globals if that file */ + extern PyObject *_Py_GetObjects(PyObject *, PyObject *); +@@ -1090,6 +1109,8 @@ static PyMethodDef sys_methods[] = { + {"settrace", sys_settrace, METH_O, settrace_doc}, + {"gettrace", sys_gettrace, METH_NOARGS, gettrace_doc}, + {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc}, ++ {"_debugmallocstats", sys_debugmallocstats, METH_VARARGS, ++ debugmallocstats_doc}, + {NULL, NULL} /* sentinel */ + }; + diff --git a/python3.spec b/python3.spec index f102431..cb64c64 100644 --- a/python3.spec +++ b/python3.spec @@ -122,7 +122,7 @@ Summary: Version 3 of the Python programming language aka Python 3000 Name: python3 Version: %{pybasever}.2 -Release: 5%{?dist} +Release: 6%{?dist} License: Python Group: Development/Languages @@ -353,6 +353,11 @@ Patch143: 00143-tsc-on-ppc.patch # (rhbz#563986) Patch146: 00146-hashlib-fips.patch +# Add a sys._debugmallocstats() function +# Based on patch 202 from RHEL 5's python.spec, with updates from rhbz#737198 +# Not yet sent upstream +Patch147: 00147-add-debug-malloc-stats.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora 17 onwards, @@ -562,6 +567,7 @@ done # 00144: not for python3 # 00145: not for python3 %patch146 -p1 +%patch147 -p1 # Currently (2010-01-15), http://docs.python.org/library is for 2.6, and there # are many differences between 2.6 and the Python 3 library. @@ -1373,6 +1379,9 @@ rm -fr %{buildroot} # ====================================================== %changelog +* Fri Sep 16 2011 David Malcolm - 3.2.2-6 +- add a sys._debugmallocstats() function (patch 147) + * Wed Sep 14 2011 David Malcolm - 3.2.2-5 - support OpenSSL FIPS mode in _hashlib and hashlib; don't build the _md5 and _sha* modules, relying on _hashlib in hashlib (rhbz#563986; patch 146)