|
|
f643203 |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
f643203 |
From: Fedora Python maintainers <python-devel@lists.fedoraproject.org>
|
|
|
f643203 |
Date: Wed, 15 Jul 2020 15:37:52 +0200
|
|
|
f643203 |
Subject: [PATCH] 00147-add-debug-malloc-stats.patch
|
|
|
f643203 |
|
|
|
f643203 |
00147 #
|
|
|
f643203 |
Add a sys._debugmallocstats() function
|
|
|
f643203 |
Based on patch 202 from RHEL 5's python.spec, with updates from rhbz#737198
|
|
|
f643203 |
Sent upstream as http://bugs.python.org/issue14785
|
|
|
f643203 |
---
|
|
|
f643203 |
Include/dictobject.h | 2 ++
|
|
|
f643203 |
Include/floatobject.h | 1 +
|
|
|
f643203 |
Include/frameobject.h | 2 ++
|
|
|
f643203 |
Include/intobject.h | 2 ++
|
|
|
f643203 |
Include/listobject.h | 2 ++
|
|
|
f643203 |
Include/methodobject.h | 4 +++
|
|
|
f643203 |
Include/object.h | 7 ++++
|
|
|
f643203 |
Include/objimpl.h | 2 +-
|
|
|
f643203 |
Include/stringobject.h | 2 ++
|
|
|
f643203 |
Include/unicodeobject.h | 2 ++
|
|
|
f643203 |
Lib/test/test_sys.py | 26 ++++++++++++++
|
|
|
f643203 |
Objects/classobject.c | 9 +++++
|
|
|
f643203 |
Objects/dictobject.c | 9 +++++
|
|
|
f643203 |
Objects/floatobject.c | 16 +++++++++
|
|
|
f643203 |
Objects/frameobject.c | 10 ++++++
|
|
|
f643203 |
Objects/intobject.c | 17 +++++++++
|
|
|
f643203 |
Objects/listobject.c | 9 +++++
|
|
|
f643203 |
Objects/methodobject.c | 9 +++++
|
|
|
f643203 |
Objects/object.c | 17 +++++++++
|
|
|
f643203 |
Objects/obmalloc.c | 80 +++++++++++++++++++++++------------------
|
|
|
f643203 |
Objects/setobject.c | 10 ++++++
|
|
|
f643203 |
Objects/stringobject.c | 40 +++++++++++++++++++++
|
|
|
f643203 |
Objects/tupleobject.c | 16 +++++++++
|
|
|
f643203 |
Objects/unicodeobject.c | 6 ++++
|
|
|
f643203 |
Python/pythonrun.c | 2 +-
|
|
|
f643203 |
Python/sysmodule.c | 53 +++++++++++++++++++++++++++
|
|
|
f643203 |
26 files changed, 319 insertions(+), 36 deletions(-)
|
|
|
f643203 |
|
|
|
f643203 |
diff --git a/Include/dictobject.h b/Include/dictobject.h
|
|
|
f643203 |
index 5a1e9feea13..da89cec6362 100644
|
|
|
f643203 |
--- a/Include/dictobject.h
|
|
|
f643203 |
+++ b/Include/dictobject.h
|
|
|
f643203 |
@@ -154,6 +154,8 @@ PyAPI_FUNC(PyObject *) PyDict_GetItemString(PyObject *dp, const char *key);
|
|
|
a43d18f |
PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item);
|
|
|
a43d18f |
PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Include/floatobject.h b/Include/floatobject.h
|
|
|
f643203 |
index 54e88256a2e..33c6ac0d78f 100644
|
|
|
f643203 |
--- a/Include/floatobject.h
|
|
|
f643203 |
+++ b/Include/floatobject.h
|
|
|
f643203 |
@@ -132,6 +132,7 @@ PyAPI_FUNC(PyObject *) _PyFloat_FormatAdvanced(PyObject *obj,
|
|
|
a43d18f |
failure. Used in builtin_round in bltinmodule.c. */
|
|
|
a43d18f |
PyAPI_FUNC(PyObject *) _Py_double_round(double x, int ndigits);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out);
|
|
|
a43d18f |
|
|
|
a43d18f |
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
f643203 |
diff --git a/Include/frameobject.h b/Include/frameobject.h
|
|
|
f643203 |
index 34603794c65..db89a4af05b 100644
|
|
|
f643203 |
--- a/Include/frameobject.h
|
|
|
f643203 |
+++ b/Include/frameobject.h
|
|
|
f643203 |
@@ -80,6 +80,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
|
|
|
a43d18f |
|
|
|
a43d18f |
PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
/* Return the line of code the frame is currently executing. */
|
|
|
a43d18f |
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
|
|
|
a43d18f |
|
|
|
f643203 |
diff --git a/Include/intobject.h b/Include/intobject.h
|
|
|
f643203 |
index d1985748b3e..60cb9e0c44b 100644
|
|
|
f643203 |
--- a/Include/intobject.h
|
|
|
f643203 |
+++ b/Include/intobject.h
|
|
|
f643203 |
@@ -78,6 +78,8 @@ PyAPI_FUNC(PyObject *) _PyInt_FormatAdvanced(PyObject *obj,
|
|
|
a43d18f |
char *format_spec,
|
|
|
a43d18f |
Py_ssize_t format_spec_len);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyInt_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Include/listobject.h b/Include/listobject.h
|
|
|
f643203 |
index f19b1c5e56c..7fccb477e1e 100644
|
|
|
f643203 |
--- a/Include/listobject.h
|
|
|
f643203 |
+++ b/Include/listobject.h
|
|
|
f643203 |
@@ -62,6 +62,8 @@ PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *);
|
|
|
a43d18f |
#define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v))
|
|
|
a43d18f |
#define PyList_GET_SIZE(op) Py_SIZE(op)
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Include/methodobject.h b/Include/methodobject.h
|
|
|
f643203 |
index 6e160b63900..1944517b392 100644
|
|
|
f643203 |
--- a/Include/methodobject.h
|
|
|
f643203 |
+++ b/Include/methodobject.h
|
|
|
a43d18f |
@@ -87,6 +87,10 @@ typedef struct {
|
|
|
a43d18f |
|
|
|
a43d18f |
PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Include/object.h b/Include/object.h
|
|
|
f643203 |
index 807b24188a7..a9d207929e0 100644
|
|
|
f643203 |
--- a/Include/object.h
|
|
|
f643203 |
+++ b/Include/object.h
|
|
|
f643203 |
@@ -1040,6 +1040,13 @@ PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void);
|
|
|
43e7c42 |
_PyTrash_thread_deposit_object((PyObject*)op); \
|
|
|
43e7c42 |
} while (0);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void)
|
|
|
a43d18f |
+_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks,
|
|
|
a43d18f |
+ size_t sizeof_block);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+PyAPI_FUNC(void)
|
|
|
a43d18f |
+_PyObject_DebugTypeStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Include/objimpl.h b/Include/objimpl.h
|
|
|
f643203 |
index cbf6bc3f876..8c14ab801a1 100644
|
|
|
f643203 |
--- a/Include/objimpl.h
|
|
|
f643203 |
+++ b/Include/objimpl.h
|
|
|
a43d18f |
@@ -101,13 +101,13 @@ PyAPI_FUNC(void) PyObject_Free(void *);
|
|
|
a43d18f |
|
|
|
a43d18f |
/* Macros */
|
|
|
a43d18f |
#ifdef WITH_PYMALLOC
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */
|
|
|
a43d18f |
PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes);
|
|
|
a43d18f |
PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes);
|
|
|
a43d18f |
PyAPI_FUNC(void) _PyObject_DebugFree(void *p);
|
|
|
a43d18f |
PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p);
|
|
|
a43d18f |
PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p);
|
|
|
a43d18f |
-PyAPI_FUNC(void) _PyObject_DebugMallocStats(void);
|
|
|
a43d18f |
PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes);
|
|
|
a43d18f |
PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes);
|
|
|
a43d18f |
PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p);
|
|
|
f643203 |
diff --git a/Include/stringobject.h b/Include/stringobject.h
|
|
|
f643203 |
index 12cc093c629..0a5fbd1c2e7 100644
|
|
|
f643203 |
--- a/Include/stringobject.h
|
|
|
f643203 |
+++ b/Include/stringobject.h
|
|
|
f643203 |
@@ -204,6 +204,8 @@ PyAPI_FUNC(PyObject *) _PyBytes_FormatAdvanced(PyObject *obj,
|
|
|
a43d18f |
char *format_spec,
|
|
|
a43d18f |
Py_ssize_t format_spec_len);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyString_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h
|
|
|
f643203 |
index 7781f966301..321bd20f2f7 100644
|
|
|
f643203 |
--- a/Include/unicodeobject.h
|
|
|
f643203 |
+++ b/Include/unicodeobject.h
|
|
|
a43d18f |
@@ -1406,6 +1406,8 @@ PyAPI_FUNC(int) _PyUnicode_IsAlpha(
|
|
|
a43d18f |
Py_UNICODE ch /* Unicode character */
|
|
|
a43d18f |
);
|
|
|
a43d18f |
|
|
|
a43d18f |
+PyAPI_FUNC(void) _PyUnicode_DebugMallocStats(FILE *out);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
|
|
|
f643203 |
index 9342716272a..331c0e9391e 100644
|
|
|
f643203 |
--- a/Lib/test/test_sys.py
|
|
|
f643203 |
+++ b/Lib/test/test_sys.py
|
|
|
f643203 |
@@ -487,6 +487,32 @@ class SysModuleTest(unittest.TestCase):
|
|
|
a43d18f |
p.wait()
|
|
|
a43d18f |
self.assertIn(executable, ["''", repr(sys.executable)])
|
|
|
a43d18f |
|
|
|
a43d18f |
+ def test_debugmallocstats(self):
|
|
|
a43d18f |
+ # Test sys._debugmallocstats()
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ import subprocess
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ # Verify the default of writing to stderr:
|
|
|
a43d18f |
+ p = subprocess.Popen([sys.executable,
|
|
|
a43d18f |
+ '-c', 'import sys; sys._debugmallocstats()'],
|
|
|
a43d18f |
+ stderr=subprocess.PIPE)
|
|
|
a43d18f |
+ out, err = p.communicate()
|
|
|
a43d18f |
+ p.wait()
|
|
|
a43d18f |
+ self.assertIn("arenas allocated current", err)
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ # Verify that we can redirect the output to a file (not a file-like
|
|
|
a43d18f |
+ # object, though):
|
|
|
a43d18f |
+ with open('mallocstats.txt', 'w') as out:
|
|
|
a43d18f |
+ sys._debugmallocstats(out)
|
|
|
a43d18f |
+ result = open('mallocstats.txt').read()
|
|
|
a43d18f |
+ self.assertIn("arenas allocated current", result)
|
|
|
a43d18f |
+ os.unlink('mallocstats.txt')
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ # Verify that the destination must be a file:
|
|
|
a43d18f |
+ with self.assertRaises(TypeError):
|
|
|
a43d18f |
+ sys._debugmallocstats(42)
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+
|
|
Matej Stuchlik |
ebcba88 |
@test.test_support.cpython_only
|
|
|
a43d18f |
class SizeofTest(unittest.TestCase):
|
|
|
f643203 |
|
|
|
f643203 |
diff --git a/Objects/classobject.c b/Objects/classobject.c
|
|
|
f643203 |
index 02d7cfd019b..1c44a4729c9 100644
|
|
|
f643203 |
--- a/Objects/classobject.c
|
|
|
f643203 |
+++ b/Objects/classobject.c
|
|
|
f643203 |
@@ -2691,3 +2691,12 @@ PyMethod_Fini(void)
|
|
|
a43d18f |
{
|
|
|
a43d18f |
(void)PyMethod_ClearFreeList();
|
|
|
a43d18f |
}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyMethod_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "free PyMethodObject",
|
|
|
a43d18f |
+ numfree, sizeof(PyMethodObject));
|
|
|
a43d18f |
+}
|
|
|
f643203 |
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
|
|
|
f643203 |
index c544ecd8c2d..89ca39c97d4 100644
|
|
|
f643203 |
--- a/Objects/dictobject.c
|
|
|
f643203 |
+++ b/Objects/dictobject.c
|
|
|
a43d18f |
@@ -225,6 +225,15 @@ show_track(void)
|
|
|
a43d18f |
static PyDictObject *free_list[PyDict_MAXFREELIST];
|
|
|
a43d18f |
static int numfree = 0;
|
|
|
a43d18f |
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyDict_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "free PyDictObject", numfree, sizeof(PyDictObject));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+
|
|
|
a43d18f |
void
|
|
|
a43d18f |
PyDict_Fini(void)
|
|
|
a43d18f |
{
|
|
|
f643203 |
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
|
|
|
f643203 |
index 5954d39cdb3..02acc8c0611 100644
|
|
|
f643203 |
--- a/Objects/floatobject.c
|
|
|
f643203 |
+++ b/Objects/floatobject.c
|
|
|
f643203 |
@@ -34,6 +34,22 @@ typedef struct _floatblock PyFloatBlock;
|
|
|
a43d18f |
static PyFloatBlock *block_list = NULL;
|
|
|
a43d18f |
static PyFloatObject *free_list = NULL;
|
|
|
a43d18f |
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyFloat_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ int num_blocks = 0;
|
|
|
a43d18f |
+ PyFloatBlock *block;
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ /* Walk the block list, counting */
|
|
|
a43d18f |
+ for (block = block_list; block ; block = block->next) {
|
|
|
a43d18f |
+ num_blocks++;
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "PyFloatBlock", num_blocks, sizeof(PyFloatBlock));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
static PyFloatObject *
|
|
|
a43d18f |
fill_free_list(void)
|
|
|
a43d18f |
{
|
|
|
f643203 |
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
|
|
|
f643203 |
index 4c91dd0c084..03a66dc9057 100644
|
|
|
f643203 |
--- a/Objects/frameobject.c
|
|
|
f643203 |
+++ b/Objects/frameobject.c
|
|
|
f643203 |
@@ -1019,3 +1019,13 @@ PyFrame_Fini(void)
|
|
|
a43d18f |
Py_XDECREF(builtin_object);
|
|
|
a43d18f |
builtin_object = NULL;
|
|
|
a43d18f |
}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyFrame_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "free PyFrameObject",
|
|
|
a43d18f |
+ numfree, sizeof(PyFrameObject));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
f643203 |
diff --git a/Objects/intobject.c b/Objects/intobject.c
|
|
|
f643203 |
index 9b27c35d88d..703fa5a5880 100644
|
|
|
f643203 |
--- a/Objects/intobject.c
|
|
|
f643203 |
+++ b/Objects/intobject.c
|
|
|
a43d18f |
@@ -44,6 +44,23 @@ typedef struct _intblock PyIntBlock;
|
|
|
a43d18f |
static PyIntBlock *block_list = NULL;
|
|
|
a43d18f |
static PyIntObject *free_list = NULL;
|
|
|
a43d18f |
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyInt_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ int num_blocks = 0;
|
|
|
a43d18f |
+ PyIntBlock *block;
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ /* Walk the block list, counting */
|
|
|
a43d18f |
+ for (block = block_list; block ; block = block->next) {
|
|
|
a43d18f |
+ num_blocks++;
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "PyIntBlock", num_blocks, sizeof(PyIntBlock));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
static PyIntObject *
|
|
|
a43d18f |
fill_free_list(void)
|
|
|
a43d18f |
{
|
|
|
f643203 |
diff --git a/Objects/listobject.c b/Objects/listobject.c
|
|
|
f643203 |
index 24eff769c64..38848bd5cf6 100644
|
|
|
f643203 |
--- a/Objects/listobject.c
|
|
|
f643203 |
+++ b/Objects/listobject.c
|
|
|
a43d18f |
@@ -109,6 +109,15 @@ PyList_Fini(void)
|
|
|
a43d18f |
}
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyList_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "free PyListObject",
|
|
|
a43d18f |
+ numfree, sizeof(PyListObject));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
PyObject *
|
|
|
a43d18f |
PyList_New(Py_ssize_t size)
|
|
|
a43d18f |
{
|
|
|
f643203 |
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
|
|
|
f643203 |
index c1a99ab2687..ea5df77ae1c 100644
|
|
|
f643203 |
--- a/Objects/methodobject.c
|
|
|
f643203 |
+++ b/Objects/methodobject.c
|
|
|
a43d18f |
@@ -412,6 +412,15 @@ PyCFunction_Fini(void)
|
|
|
a43d18f |
(void)PyCFunction_ClearFreeList();
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyCFunction_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "free PyCFunction",
|
|
|
a43d18f |
+ numfree, sizeof(PyCFunction));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
|
|
|
a43d18f |
but it's part of the API so we need to keep a function around that
|
|
|
a43d18f |
existing C extensions can call.
|
|
|
f643203 |
diff --git a/Objects/object.c b/Objects/object.c
|
|
|
f643203 |
index 65366b0b351..acef3ce32cd 100644
|
|
|
f643203 |
--- a/Objects/object.c
|
|
|
f643203 |
+++ b/Objects/object.c
|
|
|
f643203 |
@@ -2360,6 +2360,23 @@ PyMem_Free(void *p)
|
|
|
a43d18f |
PyMem_FREE(p);
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyObject_DebugTypeStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
044ee6e |
+ _PyString_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyCFunction_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyDict_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyFloat_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyFrame_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyInt_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyList_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyMethod_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PySet_DebugMallocStats(out);
|
|
|
044ee6e |
+ _PyTuple_DebugMallocStats(out);
|
|
|
a43d18f |
+#if Py_USING_UNICODE
|
|
|
044ee6e |
+ _PyUnicode_DebugMallocStats(out);
|
|
|
a43d18f |
+#endif
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
|
|
|
a43d18f |
/* These methods are used to control infinite recursion in repr, str, print,
|
|
|
a43d18f |
etc. Container objects that may recursively contain themselves,
|
|
|
f643203 |
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
|
|
|
f643203 |
index 2067cf54e74..71da93887cf 100644
|
|
|
f643203 |
--- a/Objects/obmalloc.c
|
|
|
f643203 |
+++ b/Objects/obmalloc.c
|
|
|
f643203 |
@@ -547,12 +547,10 @@ static struct arena_object* usable_arenas = NULL;
|
|
|
a43d18f |
/* Number of arenas allocated that haven't been free()'d. */
|
|
|
a43d18f |
static size_t narenas_currently_allocated = 0;
|
|
|
a43d18f |
|
|
|
a43d18f |
-#ifdef PYMALLOC_DEBUG
|
|
|
a43d18f |
/* Total number of times malloc() called to allocate an arena. */
|
|
|
a43d18f |
static size_t ntimes_arena_allocated = 0;
|
|
|
a43d18f |
/* High water mark (max value ever seen) for narenas_currently_allocated. */
|
|
|
a43d18f |
static size_t narenas_highwater = 0;
|
|
|
a43d18f |
-#endif
|
|
|
a43d18f |
|
|
|
a43d18f |
/* Allocate a new arena. If we run out of memory, return NULL. Else
|
|
|
a43d18f |
* allocate a new arena, and return the address of an arena_object
|
|
|
f643203 |
@@ -569,7 +567,7 @@ new_arena(void)
|
|
|
a43d18f |
|
|
|
a43d18f |
#ifdef PYMALLOC_DEBUG
|
|
|
a43d18f |
if (Py_GETENV("PYTHONMALLOCSTATS"))
|
|
|
a43d18f |
- _PyObject_DebugMallocStats();
|
|
|
a43d18f |
+ _PyObject_DebugMallocStats(stderr);
|
|
|
a43d18f |
#endif
|
|
|
a43d18f |
if (unused_arena_objects == NULL) {
|
|
|
a43d18f |
uint i;
|
|
|
f643203 |
@@ -637,11 +635,9 @@ new_arena(void)
|
|
Robert Kuska |
4c23f42 |
arenaobj->address = (uptr)address;
|
|
|
a43d18f |
|
|
|
a43d18f |
++narenas_currently_allocated;
|
|
|
a43d18f |
-#ifdef PYMALLOC_DEBUG
|
|
|
a43d18f |
++ntimes_arena_allocated;
|
|
|
a43d18f |
if (narenas_currently_allocated > narenas_highwater)
|
|
|
a43d18f |
narenas_highwater = narenas_currently_allocated;
|
|
|
a43d18f |
-#endif
|
|
|
a43d18f |
arenaobj->freepools = NULL;
|
|
|
a43d18f |
/* pool_address <- first pool-aligned address in the arena
|
|
|
a43d18f |
nfreepools <- number of whole pools that fit after alignment */
|
|
|
f643203 |
@@ -1802,17 +1798,19 @@ _PyObject_DebugDumpAddress(const void *p)
|
|
|
a43d18f |
}
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
+#endif /* PYMALLOC_DEBUG */
|
|
|
a43d18f |
+
|
|
|
a43d18f |
static size_t
|
|
|
a43d18f |
-printone(const char* msg, size_t value)
|
|
|
a43d18f |
+printone(FILE *out, const char* msg, size_t value)
|
|
|
a43d18f |
{
|
|
|
a43d18f |
int i, k;
|
|
|
a43d18f |
char buf[100];
|
|
|
a43d18f |
size_t origvalue = value;
|
|
|
a43d18f |
|
|
|
a43d18f |
- fputs(msg, stderr);
|
|
|
a43d18f |
+ fputs(msg, out);
|
|
|
a43d18f |
for (i = (int)strlen(msg); i < 35; ++i)
|
|
|
a43d18f |
- fputc(' ', stderr);
|
|
|
a43d18f |
- fputc('=', stderr);
|
|
|
a43d18f |
+ fputc(' ', out);
|
|
|
a43d18f |
+ fputc('=', out);
|
|
|
a43d18f |
|
|
|
a43d18f |
/* Write the value with commas. */
|
|
|
a43d18f |
i = 22;
|
|
|
f643203 |
@@ -1833,17 +1831,32 @@ printone(const char* msg, size_t value)
|
|
|
a43d18f |
|
|
|
a43d18f |
while (i >= 0)
|
|
|
a43d18f |
buf[i--] = ' ';
|
|
|
a43d18f |
- fputs(buf, stderr);
|
|
|
a43d18f |
+ fputs(buf, out);
|
|
|
a43d18f |
|
|
|
a43d18f |
return origvalue;
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
-/* Print summary info to stderr about the state of pymalloc's structures.
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyDebugAllocatorStats(FILE *out,
|
|
|
a43d18f |
+ const char *block_name, int num_blocks, size_t sizeof_block)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ char buf1[128];
|
|
|
a43d18f |
+ char buf2[128];
|
|
|
a43d18f |
+ PyOS_snprintf(buf1, sizeof(buf1),
|
|
|
a43d18f |
+ "%d %ss * %zd bytes each",
|
|
|
a43d18f |
+ num_blocks, block_name, sizeof_block);
|
|
|
a43d18f |
+ PyOS_snprintf(buf2, sizeof(buf2),
|
|
|
a43d18f |
+ "%48s ", buf1);
|
|
|
a43d18f |
+ (void)printone(out, buf2, num_blocks * sizeof_block);
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+/* Print summary info to "out" about the state of pymalloc's structures.
|
|
|
a43d18f |
* In Py_DEBUG mode, also perform some expensive internal consistency
|
|
|
a43d18f |
* checks.
|
|
|
a43d18f |
*/
|
|
|
a43d18f |
void
|
|
|
a43d18f |
-_PyObject_DebugMallocStats(void)
|
|
|
a43d18f |
+_PyObject_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
{
|
|
|
a43d18f |
uint i;
|
|
|
a43d18f |
const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
|
|
|
f643203 |
@@ -1872,7 +1885,7 @@ _PyObject_DebugMallocStats(void)
|
|
|
a43d18f |
size_t total;
|
|
|
a43d18f |
char buf[128];
|
|
|
a43d18f |
|
|
|
a43d18f |
- fprintf(stderr, "Small block threshold = %d, in %u size classes.\n",
|
|
|
a43d18f |
+ fprintf(out, "Small block threshold = %d, in %u size classes.\n",
|
|
|
a43d18f |
SMALL_REQUEST_THRESHOLD, numclasses);
|
|
|
a43d18f |
|
|
|
a43d18f |
for (i = 0; i < numclasses; ++i)
|
|
|
f643203 |
@@ -1926,10 +1939,10 @@ _PyObject_DebugMallocStats(void)
|
|
|
a43d18f |
}
|
|
|
a43d18f |
assert(narenas == narenas_currently_allocated);
|
|
|
a43d18f |
|
|
|
a43d18f |
- fputc('\n', stderr);
|
|
|
a43d18f |
+ fputc('\n', out);
|
|
|
a43d18f |
fputs("class size num pools blocks in use avail blocks\n"
|
|
|
a43d18f |
"----- ---- --------- ------------- ------------\n",
|
|
|
a43d18f |
- stderr);
|
|
|
a43d18f |
+ out);
|
|
|
a43d18f |
|
|
|
a43d18f |
for (i = 0; i < numclasses; ++i) {
|
|
|
a43d18f |
size_t p = numpools[i];
|
|
|
f643203 |
@@ -1940,7 +1953,7 @@ _PyObject_DebugMallocStats(void)
|
|
|
a43d18f |
assert(b == 0 && f == 0);
|
|
|
a43d18f |
continue;
|
|
|
a43d18f |
}
|
|
|
a43d18f |
- fprintf(stderr, "%5u %6u "
|
|
|
a43d18f |
+ fprintf(out, "%5u %6u "
|
|
|
a43d18f |
"%11" PY_FORMAT_SIZE_T "u "
|
|
|
a43d18f |
"%15" PY_FORMAT_SIZE_T "u "
|
|
|
a43d18f |
"%13" PY_FORMAT_SIZE_T "u\n",
|
|
|
f643203 |
@@ -1950,36 +1963,35 @@ _PyObject_DebugMallocStats(void)
|
|
|
a43d18f |
pool_header_bytes += p * POOL_OVERHEAD;
|
|
|
a43d18f |
quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size);
|
|
|
a43d18f |
}
|
|
|
a43d18f |
- fputc('\n', stderr);
|
|
|
a43d18f |
- (void)printone("# times object malloc called", serialno);
|
|
|
a43d18f |
-
|
|
|
a43d18f |
- (void)printone("# arenas allocated total", ntimes_arena_allocated);
|
|
|
a43d18f |
- (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas);
|
|
|
a43d18f |
- (void)printone("# arenas highwater mark", narenas_highwater);
|
|
|
a43d18f |
- (void)printone("# arenas allocated current", narenas);
|
|
|
a43d18f |
+ fputc('\n', out);
|
|
|
a43d18f |
+#ifdef PYMALLOC_DEBUG
|
|
|
a43d18f |
+ (void)printone(out, "# times object malloc called", serialno);
|
|
|
a43d18f |
+#endif
|
|
|
a43d18f |
+ (void)printone(out, "# arenas allocated total", ntimes_arena_allocated);
|
|
|
a43d18f |
+ (void)printone(out, "# arenas reclaimed", ntimes_arena_allocated - narenas);
|
|
|
a43d18f |
+ (void)printone(out, "# arenas highwater mark", narenas_highwater);
|
|
|
a43d18f |
+ (void)printone(out, "# arenas allocated current", narenas);
|
|
|
a43d18f |
|
|
|
a43d18f |
PyOS_snprintf(buf, sizeof(buf),
|
|
|
a43d18f |
"%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena",
|
|
|
a43d18f |
narenas, ARENA_SIZE);
|
|
|
a43d18f |
- (void)printone(buf, narenas * ARENA_SIZE);
|
|
|
a43d18f |
+ (void)printone(out, buf, narenas * ARENA_SIZE);
|
|
|
a43d18f |
|
|
|
a43d18f |
- fputc('\n', stderr);
|
|
|
a43d18f |
+ fputc('\n', out);
|
|
|
a43d18f |
|
|
|
a43d18f |
- total = printone("# bytes in allocated blocks", allocated_bytes);
|
|
|
a43d18f |
- total += printone("# bytes in available blocks", available_bytes);
|
|
|
a43d18f |
+ total = printone(out, "# bytes in allocated blocks", allocated_bytes);
|
|
|
a43d18f |
+ total += printone(out, "# bytes in available blocks", available_bytes);
|
|
|
a43d18f |
|
|
|
a43d18f |
PyOS_snprintf(buf, sizeof(buf),
|
|
|
a43d18f |
"%u unused pools * %d bytes", numfreepools, POOL_SIZE);
|
|
|
a43d18f |
- total += printone(buf, (size_t)numfreepools * POOL_SIZE);
|
|
|
a43d18f |
+ total += printone(out, buf, (size_t)numfreepools * POOL_SIZE);
|
|
|
a43d18f |
|
|
|
a43d18f |
- total += printone("# bytes lost to pool headers", pool_header_bytes);
|
|
|
a43d18f |
- total += printone("# bytes lost to quantization", quantization);
|
|
|
a43d18f |
- total += printone("# bytes lost to arena alignment", arena_alignment);
|
|
|
a43d18f |
- (void)printone("Total", total);
|
|
|
a43d18f |
+ total += printone(out, "# bytes lost to pool headers", pool_header_bytes);
|
|
|
a43d18f |
+ total += printone(out, "# bytes lost to quantization", quantization);
|
|
|
a43d18f |
+ total += printone(out, "# bytes lost to arena alignment", arena_alignment);
|
|
|
a43d18f |
+ (void)printone(out, "Total", total);
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
-#endif /* PYMALLOC_DEBUG */
|
|
|
a43d18f |
-
|
|
|
a43d18f |
#ifdef Py_USING_MEMORY_DEBUGGER
|
|
|
a43d18f |
/* Make this function last so gcc won't inline it since the definition is
|
|
|
a43d18f |
* after the reference.
|
|
|
f643203 |
diff --git a/Objects/setobject.c b/Objects/setobject.c
|
|
|
f643203 |
index 31da3dbfecb..da086ab2bdb 100644
|
|
|
f643203 |
--- a/Objects/setobject.c
|
|
|
f643203 |
+++ b/Objects/setobject.c
|
|
|
f643203 |
@@ -1087,6 +1087,16 @@ PySet_Fini(void)
|
|
|
a43d18f |
Py_CLEAR(emptyfrozenset);
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PySet_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ "free PySetObject",
|
|
|
a43d18f |
+ numfree, sizeof(PySetObject));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+
|
|
|
a43d18f |
static PyObject *
|
|
|
a43d18f |
set_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
a43d18f |
{
|
|
|
f643203 |
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
|
|
|
f643203 |
index c47d32f4060..b1ffa249745 100644
|
|
|
f643203 |
--- a/Objects/stringobject.c
|
|
|
f643203 |
+++ b/Objects/stringobject.c
|
|
|
f643203 |
@@ -4880,3 +4880,43 @@ void _Py_ReleaseInternedStrings(void)
|
|
|
43e7c42 |
PyDict_Clear(interned);
|
|
|
43e7c42 |
Py_CLEAR(interned);
|
|
|
a43d18f |
}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+void _PyString_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ ssize_t i;
|
|
|
a43d18f |
+ int num_immortal = 0, num_mortal = 0;
|
|
|
a43d18f |
+ ssize_t immortal_size = 0, mortal_size = 0;
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ if (interned == NULL || !PyDict_Check(interned))
|
|
|
a43d18f |
+ return;
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ for (i = 0; i <= ((PyDictObject*)interned)->ma_mask; i++) {
|
|
|
a43d18f |
+ PyDictEntry *ep = ((PyDictObject*)interned)->ma_table + i;
|
|
|
a43d18f |
+ PyObject *pvalue = ep->me_value;
|
|
|
a43d18f |
+ if (pvalue != NULL) {
|
|
|
a43d18f |
+ PyStringObject *s = (PyStringObject *)ep->me_key;
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ switch (s->ob_sstate) {
|
|
|
a43d18f |
+ case SSTATE_NOT_INTERNED:
|
|
|
a43d18f |
+ /* XXX Shouldn't happen */
|
|
|
a43d18f |
+ break;
|
|
|
a43d18f |
+ case SSTATE_INTERNED_IMMORTAL:
|
|
|
a43d18f |
+ num_immortal ++;
|
|
|
a43d18f |
+ immortal_size += s->ob_size;
|
|
|
a43d18f |
+ break;
|
|
|
a43d18f |
+ case SSTATE_INTERNED_MORTAL:
|
|
|
a43d18f |
+ num_mortal ++;
|
|
|
a43d18f |
+ mortal_size += s->ob_size;
|
|
|
a43d18f |
+ break;
|
|
|
a43d18f |
+ default:
|
|
|
a43d18f |
+ Py_FatalError("Inconsistent interned string state.");
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ fprintf(out, "%d mortal interned strings\n", num_mortal);
|
|
|
a43d18f |
+ fprintf(out, "%d immortal interned strings\n", num_immortal);
|
|
|
a43d18f |
+ fprintf(out, "total size of all interned strings: "
|
|
|
a43d18f |
+ "%zi/%zi "
|
|
|
a43d18f |
+ "mortal/immortal\n", mortal_size, immortal_size);
|
|
|
a43d18f |
+}
|
|
|
f643203 |
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
|
|
|
f643203 |
index 6f4b18cc5c6..e8e44901589 100644
|
|
|
f643203 |
--- a/Objects/tupleobject.c
|
|
|
f643203 |
+++ b/Objects/tupleobject.c
|
|
|
a43d18f |
@@ -44,6 +44,22 @@ show_track(void)
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
a43d18f |
|
|
|
a43d18f |
+/* Print summary info about the state of the optimized allocator */
|
|
|
a43d18f |
+void
|
|
|
a43d18f |
+_PyTuple_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+#if PyTuple_MAXSAVESIZE > 0
|
|
|
a43d18f |
+ int i;
|
|
|
a43d18f |
+ char buf[128];
|
|
|
a43d18f |
+ for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
|
|
|
a43d18f |
+ PyOS_snprintf(buf, sizeof(buf),
|
|
|
a43d18f |
+ "free %d-sized PyTupleObject", i);
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out,
|
|
|
a43d18f |
+ buf,
|
|
|
a43d18f |
+ numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i));
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+#endif
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
|
|
|
a43d18f |
PyObject *
|
|
|
a43d18f |
PyTuple_New(register Py_ssize_t size)
|
|
|
f643203 |
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
|
|
|
f643203 |
index a859fa05214..b6ff83e110e 100644
|
|
|
f643203 |
--- a/Objects/unicodeobject.c
|
|
|
f643203 |
+++ b/Objects/unicodeobject.c
|
|
|
f643203 |
@@ -9018,6 +9018,12 @@ _PyUnicode_Fini(void)
|
|
|
a43d18f |
(void)PyUnicode_ClearFreeList();
|
|
|
a43d18f |
}
|
|
|
a43d18f |
|
|
|
a43d18f |
+void _PyUnicode_DebugMallocStats(FILE *out)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ _PyDebugAllocatorStats(out, "free PyUnicodeObject", numfree,
|
|
|
a43d18f |
+ sizeof(PyUnicodeObject));
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef __cplusplus
|
|
|
a43d18f |
}
|
|
|
a43d18f |
#endif
|
|
|
f643203 |
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
|
|
|
f643203 |
index abdfb146ae5..d9a0e98a9e9 100644
|
|
|
f643203 |
--- a/Python/pythonrun.c
|
|
|
f643203 |
+++ b/Python/pythonrun.c
|
|
|
f643203 |
@@ -562,7 +562,7 @@ Py_Finalize(void)
|
|
|
044ee6e |
#endif /* Py_TRACE_REFS */
|
|
|
044ee6e |
#ifdef PYMALLOC_DEBUG
|
|
|
044ee6e |
if (Py_GETENV("PYTHONMALLOCSTATS"))
|
|
|
044ee6e |
- _PyObject_DebugMallocStats();
|
|
|
044ee6e |
+ _PyObject_DebugMallocStats(stderr);
|
|
|
044ee6e |
#endif
|
|
|
044ee6e |
|
|
|
044ee6e |
call_ll_exitfuncs();
|
|
|
f643203 |
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
|
|
|
f643203 |
index 22238ba8ce4..95bfb40bee7 100644
|
|
|
f643203 |
--- a/Python/sysmodule.c
|
|
|
f643203 |
+++ b/Python/sysmodule.c
|
|
|
f643203 |
@@ -890,6 +890,57 @@ a 11-tuple where the entries in the tuple are counts of:\n\
|
|
|
a43d18f |
extern "C" {
|
|
|
a43d18f |
#endif
|
|
|
a43d18f |
|
|
|
a43d18f |
+static PyObject *
|
|
|
a43d18f |
+sys_debugmallocstats(PyObject *self, PyObject *args)
|
|
|
a43d18f |
+{
|
|
|
a43d18f |
+ PyObject *file = NULL;
|
|
|
a43d18f |
+ FILE *fp;
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ if (!PyArg_ParseTuple(args, "|O!",
|
|
|
a43d18f |
+ &PyFile_Type, &file)) {
|
|
|
a43d18f |
+ return NULL;
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+ if (!file) {
|
|
|
a43d18f |
+ /* Default to sys.stderr: */
|
|
|
a43d18f |
+ file = PySys_GetObject("stderr");
|
|
|
a43d18f |
+ if (!file) {
|
|
|
a43d18f |
+ PyErr_SetString(PyExc_ValueError, "sys.stderr not set");
|
|
|
a43d18f |
+ return NULL;
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+ if (!PyFile_Check(file)) {
|
|
|
a43d18f |
+ PyErr_SetString(PyExc_TypeError, "sys.stderr is not a file");
|
|
|
a43d18f |
+ return NULL;
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ Py_INCREF(file);
|
|
|
a43d18f |
+ /* OK, we now own a ref on non-NULL "file" */
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ fp = PyFile_AsFile(file);
|
|
|
a43d18f |
+ if (!fp) {
|
|
|
a43d18f |
+ PyErr_SetString(PyExc_ValueError, "file is closed");
|
|
|
a43d18f |
+ Py_DECREF(file);
|
|
|
a43d18f |
+ return NULL;
|
|
|
a43d18f |
+ }
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ _PyObject_DebugMallocStats(fp);
|
|
|
a43d18f |
+ fputc('\n', fp);
|
|
|
a43d18f |
+ _PyObject_DebugTypeStats(fp);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ Py_DECREF(file);
|
|
|
a43d18f |
+
|
|
|
a43d18f |
+ Py_RETURN_NONE;
|
|
|
a43d18f |
+}
|
|
|
a43d18f |
+PyDoc_STRVAR(debugmallocstats_doc,
|
|
|
a43d18f |
+"_debugmallocstats([file])\n\
|
|
|
a43d18f |
+\n\
|
|
|
a43d18f |
+Print summary info to the given file (or sys.stderr) about the state of\n\
|
|
|
a43d18f |
+pymalloc's structures.\n\
|
|
|
a43d18f |
+\n\
|
|
|
a43d18f |
+In Py_DEBUG mode, also perform some expensive internal consistency\n\
|
|
|
a43d18f |
+checks.\n\
|
|
|
a43d18f |
+");
|
|
|
a43d18f |
+
|
|
|
a43d18f |
#ifdef Py_TRACE_REFS
|
|
|
a43d18f |
/* Defined in objects.c because it uses static globals if that file */
|
|
|
a43d18f |
extern PyObject *_Py_GetObjects(PyObject *, PyObject *);
|
|
|
f643203 |
@@ -988,6 +1039,8 @@ static PyMethodDef sys_methods[] = {
|
|
|
a43d18f |
{"settrace", sys_settrace, METH_O, settrace_doc},
|
|
|
a43d18f |
{"gettrace", sys_gettrace, METH_NOARGS, gettrace_doc},
|
|
|
a43d18f |
{"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
|
|
|
a43d18f |
+ {"_debugmallocstats", sys_debugmallocstats, METH_VARARGS,
|
|
|
a43d18f |
+ debugmallocstats_doc},
|
|
|
a43d18f |
{NULL, NULL} /* sentinel */
|
|
|
a43d18f |
};
|
|
|
a43d18f |
|