diff options
34 files changed, 24 insertions, 469 deletions
diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 108bd2c..c589a6f 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -627,14 +627,6 @@ PyConfig ``python3 -m MODULE`` argument. Used by :c:func:`Py_RunMain`. - .. c:member:: int show_alloc_count - - Show allocation counts at exit? - - Set to 1 by :option:`-X showalloccount <-X>` command line option. - - Need a special Python build with ``COUNT_ALLOCS`` macro defined. - .. c:member:: int show_ref_count Show total reference count at exit? @@ -702,6 +694,10 @@ arguments are stripped from ``argv``: see :ref:`Command Line Arguments The ``xoptions`` options are parsed to set other options: see :option:`-X` option. +.. versionchanged:: 3.9 + + The ``show_alloc_count`` field has been removed. + Initialization with PyConfig ---------------------------- diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 7b205c0..a8a779e 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -148,15 +148,6 @@ Quick Reference | :c:member:`~PyTypeObject.tp_vectorcall` | :c:type:`vectorcallfunc` | | | | | | +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ -If :const:`COUNT_ALLOCS` is defined then the following (internal-only) -fields exist as well: - -* :c:member:`~PyTypeObject.tp_allocs` -* :c:member:`~PyTypeObject.tp_frees` -* :c:member:`~PyTypeObject.tp_maxalloc` -* :c:member:`~PyTypeObject.tp_prev` -* :c:member:`~PyTypeObject.tp_next` - .. [#slots] A slot name in parentheses indicates it is (effectively) deprecated. Names in angle brackets should be treated as read-only. @@ -1904,31 +1895,6 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. versionadded:: 3.9 (the field exists since 3.8 but it's only used since 3.9) -The remaining fields are only defined if the feature test macro -:const:`COUNT_ALLOCS` is defined, and are for internal use only. They are -documented here for completeness. None of these fields are inherited by -subtypes. - -.. c:member:: Py_ssize_t PyTypeObject.tp_allocs - - Number of allocations. - -.. c:member:: Py_ssize_t PyTypeObject.tp_frees - - Number of frees. - -.. c:member:: Py_ssize_t PyTypeObject.tp_maxalloc - - Maximum simultaneously allocated objects. - -.. c:member:: PyTypeObject* PyTypeObject.tp_prev - - Pointer to the previous type object with a non-zero :c:member:`~PyTypeObject.tp_allocs` field. - -.. c:member:: PyTypeObject* PyTypeObject.tp_next - - Pointer to the next type object with a non-zero :c:member:`~PyTypeObject.tp_allocs` field. - Also, note that, in a garbage collected Python, :c:member:`~PyTypeObject.tp_dealloc` may be called from any Python thread, not just the thread which created the object (if the object becomes part of a refcount cycle, that cycle might be collected by a garbage diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index fb88673..2206e50 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -434,9 +434,6 @@ Miscellaneous options stored in a traceback of a trace. Use ``-X tracemalloc=NFRAME`` to start tracing with a traceback limit of *NFRAME* frames. See the :func:`tracemalloc.start` for more information. - * ``-X showalloccount`` to output the total count of allocated objects for - each type when the program finishes. This only works when Python was built with - ``COUNT_ALLOCS`` defined. * ``-X importtime`` to show how long each import takes. It shows module name, cumulative time (including nested imports) and self time (excluding nested imports). Note that its output may be broken in multi-threaded @@ -479,6 +476,8 @@ Miscellaneous options Using ``-X dev`` option, check *encoding* and *errors* arguments on string encoding and decoding operations. + The ``-X showalloccount`` option has been removed. + Options you shouldn't use ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 931f8bf..3b7a9d1 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -348,6 +348,9 @@ Build and C API Changes functions are now required to build Python. (Contributed by Victor Stinner in :issue:`39395`.) +* The ``COUNT_ALLOCS`` special build macro has been removed. + (Contributed by Victor Stinner in :issue:`39489`.) + Deprecated ========== @@ -484,6 +487,12 @@ Removed ``asyncio.Condition`` and ``asyncio.Semaphore``. (Contributed by Andrew Svetlov in :issue:`34793`.) +* The :func:`sys.getcounts` function, the ``-X showalloccount`` command line + option and the ``show_alloc_count`` field of the C structure + :c:type:`PyConfig` have been removed. They required a special Python build by + defining ``COUNT_ALLOCS`` macro. + (Contributed by Victor Stinner in :issue:`39489`.) + Porting to Python 3.9 ===================== diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index 54e6623..c5fa2b3 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -153,7 +153,6 @@ typedef struct { int import_time; /* PYTHONPROFILEIMPORTTIME, -X importtime */ int show_ref_count; /* -X showrefcount */ - int show_alloc_count; /* -X showalloccount */ int dump_refs; /* PYTHONDUMPREFS */ int malloc_stats; /* PYTHONMALLOCSTATS */ diff --git a/Include/cpython/object.h b/Include/cpython/object.h index dc8fd6f..5fcad55 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -255,15 +255,6 @@ typedef struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; - -#ifdef COUNT_ALLOCS - /* these must be last and never explicitly initialized */ - Py_ssize_t tp_allocs; - Py_ssize_t tp_frees; - Py_ssize_t tp_maxalloc; - struct _typeobject *tp_prev; - struct _typeobject *tp_next; -#endif } PyTypeObject; /* The *real* layout of a type object when allocated on the heap */ @@ -341,8 +332,6 @@ static inline void _Py_Dealloc_inline(PyObject *op) destructor dealloc = Py_TYPE(op)->tp_dealloc; #ifdef Py_TRACE_REFS _Py_ForgetReference(op); -#else - _Py_INC_TPFREES(op); #endif (*dealloc)(op); } diff --git a/Include/object.h b/Include/object.h index 7a5f573..1a2e704 100644 --- a/Include/object.h +++ b/Include/object.h @@ -405,20 +405,6 @@ PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void); #define _Py_DEC_REFTOTAL #endif /* Py_REF_DEBUG */ -#ifdef COUNT_ALLOCS -PyAPI_FUNC(void) _Py_inc_count(struct _typeobject *); -PyAPI_FUNC(void) _Py_dec_count(struct _typeobject *); -#define _Py_INC_TPALLOCS(OP) _Py_inc_count(Py_TYPE(OP)) -#define _Py_INC_TPFREES(OP) _Py_dec_count(Py_TYPE(OP)) -#define _Py_DEC_TPFREES(OP) Py_TYPE(OP)->tp_frees-- -#define _Py_COUNT_ALLOCS_COMMA , -#else -#define _Py_INC_TPALLOCS(OP) -#define _Py_INC_TPFREES(OP) -#define _Py_DEC_TPFREES(OP) -#define _Py_COUNT_ALLOCS_COMMA -#endif /* COUNT_ALLOCS */ - /* Update the Python traceback of an object. This function must be called when a memory block is reused from a free list. */ PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op); @@ -438,15 +424,13 @@ static inline void _Py_NewReference(PyObject *op) if (_Py_tracemalloc_config.tracing) { _PyTraceMalloc_NewReference(op); } - _Py_INC_TPALLOCS(op); _Py_INC_REFTOTAL; Py_REFCNT(op) = 1; } -static inline void _Py_ForgetReference(PyObject *op) +static inline void _Py_ForgetReference(PyObject *Py_UNUSED(op)) { - (void)op; /* may be unused, shut up -Wunused-parameter */ - _Py_INC_TPFREES(op); + /* nothing to do */ } #endif /* !Py_TRACE_REFS */ diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 26a1e69..c8db387 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -325,7 +325,7 @@ def _args_from_interpreter_flags(): if dev_mode: args.extend(('-X', 'dev')) for opt in ('faulthandler', 'tracemalloc', 'importtime', - 'showalloccount', 'showrefcount', 'utf8'): + 'showrefcount', 'utf8'): if opt in xoptions: value = xoptions[opt] if value is True: diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 215bab8..259c706 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2512,9 +2512,6 @@ def swap_item(obj, item, new_val): if item in obj: del obj[item] -requires_type_collecting = unittest.skipIf(hasattr(sys, 'getcounts'), - 'types are immortal if COUNT_ALLOCS is defined') - def args_from_interpreter_flags(): """Return a list of command-line arguments reproducing the current settings in sys.flags and sys.warnoptions.""" diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 73ef962..87842b9 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -356,7 +356,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'tracemalloc': 0, 'import_time': 0, 'show_ref_count': 0, - 'show_alloc_count': 0, 'dump_refs': 0, 'malloc_stats': 0, @@ -729,7 +728,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'tracemalloc': 2, 'import_time': 1, 'show_ref_count': 1, - 'show_alloc_count': 1, 'malloc_stats': 1, 'stdio_encoding': 'iso8859-1', diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index 18f8d10..acb6391 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -2,7 +2,7 @@ import unittest import unittest.mock from test.support import (verbose, refcount_test, run_unittest, cpython_only, start_threads, - temp_dir, requires_type_collecting, TESTFN, unlink, + temp_dir, TESTFN, unlink, import_module) from test.support.script_helper import assert_python_ok, make_script @@ -131,7 +131,6 @@ class GCTests(unittest.TestCase): del a self.assertNotEqual(gc.collect(), 0) - @requires_type_collecting def test_newinstance(self): class A(object): pass @@ -709,7 +708,6 @@ class GCTests(unittest.TestCase): stderr = run_command(code % "gc.DEBUG_SAVEALL") self.assertNotIn(b"uncollectable objects at shutdown", stderr) - @requires_type_collecting def test_gc_main_module_at_shutdown(self): # Create a reference cycle through the __main__ module and check # it gets collected at interpreter shutdown. @@ -723,7 +721,6 @@ class GCTests(unittest.TestCase): rc, out, err = assert_python_ok('-c', code) self.assertEqual(out.strip(), b'__del__ called') - @requires_type_collecting def test_gc_ordinary_module_at_shutdown(self): # Same as above, but with a non-__main__ module. with temp_dir() as script_dir: @@ -743,7 +740,6 @@ class GCTests(unittest.TestCase): rc, out, err = assert_python_ok('-c', code) self.assertEqual(out.strip(), b'__del__ called') - @requires_type_collecting def test_global_del_SystemExit(self): code = """if 1: class ClassWithDel: diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 501e931..8a123fa 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -3492,7 +3492,6 @@ class TextIOWrapperTest(unittest.TestCase): """.format(iomod=iomod, kwargs=kwargs) return assert_python_ok("-c", code) - @support.requires_type_collecting def test_create_at_shutdown_without_encoding(self): rc, out, err = self._check_create_at_shutdown() if err: @@ -3502,7 +3501,6 @@ class TextIOWrapperTest(unittest.TestCase): else: self.assertEqual("ok", out.decode().strip()) - @support.requires_type_collecting def test_create_at_shutdown_with_encoding(self): rc, out, err = self._check_create_at_shutdown(encoding='utf-8', errors='strict') diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index c38fdae..e223522 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4252,7 +4252,6 @@ class ModuleLevelMiscTest(BaseTest): h.close() logging.setLoggerClass(logging.Logger) - @support.requires_type_collecting def test_logging_at_shutdown(self): # Issue #20037 code = """if 1: diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py index efe9a8e..1d44563 100644 --- a/Lib/test/test_module.py +++ b/Lib/test/test_module.py @@ -1,7 +1,7 @@ # Test the module type import unittest import weakref -from test.support import gc_collect, requires_type_collecting +from test.support import gc_collect from test.support.script_helper import assert_python_ok import sys @@ -101,7 +101,6 @@ class ModuleTests(unittest.TestCase): gc_collect() self.assertEqual(f().__dict__["bar"], 4) - @requires_type_collecting def test_clear_dict_in_ref_cycle(self): destroyed = [] m = ModuleType("foo") @@ -266,7 +265,6 @@ a = A(destroyed)""" self.assertEqual(r[-len(ends_with):], ends_with, '{!r} does not end with {!r}'.format(r, ends_with)) - @requires_type_collecting def test_module_finalization_at_shutdown(self): # Module globals and builtins should still be available during shutdown rc, out, err = assert_python_ok("-c", "from test import final_a") diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 2f347bd..175f7c8 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -493,7 +493,6 @@ class TestSupport(unittest.TestCase): ['-Wignore', '-X', 'dev'], ['-X', 'faulthandler'], ['-X', 'importtime'], - ['-X', 'showalloccount'], ['-X', 'showrefcount'], ['-X', 'tracemalloc'], ['-X', 'tracemalloc=3'], diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 947c935..58701a1 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -819,7 +819,6 @@ class SysModuleTest(unittest.TestCase): c = sys.getallocatedblocks() self.assertIn(c, range(b - 50, b + 50)) - @test.support.requires_type_collecting def test_is_finalizing(self): self.assertIs(sys.is_finalizing(), False) # Don't use the atexit module because _Py_Finalizing is only set @@ -841,7 +840,6 @@ class SysModuleTest(unittest.TestCase): rc, stdout, stderr = assert_python_ok('-c', code) self.assertEqual(stdout.rstrip(), b'True') - @test.support.requires_type_collecting def test_issue20602(self): # sys.flags and sys.float_info were wiped during shutdown. code = """if 1: @@ -1295,8 +1293,6 @@ class SizeofTest(unittest.TestCase): # type # static type: PyTypeObject fmt = 'P2nPI13Pl4Pn9Pn11PIPP' - if hasattr(sys, 'getcounts'): - fmt += '3n2P' s = vsize(fmt) check(int, s) # class diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 62f2d54..a9d31af 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -3,8 +3,7 @@ Tests for the threading module. """ import test.support -from test.support import (verbose, import_module, cpython_only, - requires_type_collecting) +from test.support import verbose, import_module, cpython_only from test.support.script_helper import assert_python_ok, assert_python_failure import random @@ -552,7 +551,6 @@ class ThreadTests(BaseTestCase): self.assertEqual(err, b"") self.assertEqual(data, "Thread-1\nTrue\nTrue\n") - @requires_type_collecting def test_main_thread_during_shutdown(self): # bpo-31516: current_thread() should still point to the main thread # at shutdown @@ -1113,7 +1111,6 @@ class ThreadingExceptionTests(BaseTestCase): self.assertIn("ZeroDivisionError", err) self.assertNotIn("Unhandled exception", err) - @requires_type_collecting def test_print_exception_stderr_is_none_1(self): script = r"""if True: import sys diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7135d99..60e0b58 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -174,7 +174,6 @@ class TracebackCases(unittest.TestCase): # Issue #18960: coding spec should have no effect do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5) - @support.requires_type_collecting def test_print_traceback_at_exit(self): # Issue #22599: Ensure that it is possible to use the traceback module # to display an exception at Python exit diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index c6fb097..268ecb0 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1227,7 +1227,6 @@ class BootstrapTest(unittest.TestCase): class FinalizationTest(unittest.TestCase): - @support.requires_type_collecting def test_finalization(self): # Issue #19421: warnings.warn() should not crash # during Python finalization diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 228bc17..63c7255 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -649,7 +649,6 @@ class ReferencesTestCase(TestBase): del c1, c2, C, D gc.collect() - @support.requires_type_collecting def test_callback_in_cycle_resurrection(self): import gc diff --git a/Misc/NEWS.d/next/Build/2020-01-29-19-17-02.bpo-39489.HKPzv-.rst b/Misc/NEWS.d/next/Build/2020-01-29-19-17-02.bpo-39489.HKPzv-.rst new file mode 100644 index 0000000..652a435 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2020-01-29-19-17-02.bpo-39489.HKPzv-.rst @@ -0,0 +1 @@ +Remove ``COUNT_ALLOCS`` special build. diff --git a/Misc/SpecialBuilds.txt b/Misc/SpecialBuilds.txt index d1a0321..27369ab 100644 --- a/Misc/SpecialBuilds.txt +++ b/Misc/SpecialBuilds.txt @@ -46,9 +46,7 @@ Build option: ``./configure --with-trace-refs``. Turn on heavy reference debugging. This is major surgery. Every PyObject grows two more pointers, to maintain a doubly-linked list of all live heap-allocated objects. Most built-in type objects are not in this list, as they're statically -allocated. Starting in Python 2.3, if COUNT_ALLOCS (see below) is also defined, -a static type object T does appear in this list if at least one object of type T -has been created. +allocated. Note that because the fundamental PyObject layout changes, Python modules compiled with Py_TRACE_REFS are incompatible with modules compiled without it. @@ -165,55 +163,6 @@ by not defining NDEBUG), and some routines do additional sanity checks inside "#ifdef Py_DEBUG" blocks. -COUNT_ALLOCS ------------- - -Each type object grows three new members: - - /* Number of times an object of this type was allocated. */ - int tp_allocs; - - /* Number of times an object of this type was deallocated. */ - int tp_frees; - - /* Highwater mark: the maximum value of tp_allocs - tp_frees so - * far; or, IOW, the largest number of objects of this type alive at - * the same time. - */ - int tp_maxalloc; - -Allocation and deallocation code keeps these counts up to date. Py_FinalizeEx() -displays a summary of the info returned by sys.getcounts() (see below), along -with assorted other special allocation counts (like the number of tuple -allocations satisfied by a tuple free-list, the number of 1-character strings -allocated, etc). - -Before Python 2.2, type objects were immortal, and the COUNT_ALLOCS -implementation relies on that. As of Python 2.2, heap-allocated type/ class -objects can go away. COUNT_ALLOCS can blow up in 2.2 and 2.2.1 because of this; -this was fixed in 2.2.2. Use of COUNT_ALLOCS makes all heap-allocated type -objects immortal, except for those for which no object of that type is ever -allocated. - -Starting with Python 2.3, If Py_TRACE_REFS is also defined, COUNT_ALLOCS -arranges to ensure that the type object for each allocated object appears in the -doubly-linked list of all objects maintained by Py_TRACE_REFS. - -Special gimmicks: - -sys.getcounts() - Return a list of 4-tuples, one entry for each type object for which at least - one object of that type was allocated. Each tuple is of the form: - - (tp_name, tp_allocs, tp_frees, tp_maxalloc) - - Each distinct type object gets a distinct entry in this list, even if two or - more type objects have the same tp_name (in which case there's no way to - distinguish them by looking at this list). The list is ordered by time of - first object allocation: the type object for which the first allocation of - an object of that type occurred most recently is at the front of the list. - - LLTRACE ------- diff --git a/Misc/python.man b/Misc/python.man index 3645b02..89a15a5 100644 --- a/Misc/python.man +++ b/Misc/python.man @@ -286,10 +286,6 @@ Set implementation specific option. The following options are available: traceback of a trace. Use -X tracemalloc=NFRAME to start tracing with a traceback limit of NFRAME frames - -X showalloccount: output the total count of allocated objects for each - type when the program finishes. This only works when Python was built with - COUNT_ALLOCS defined - -X importtime: show how long each import takes. It shows module name, cumulative time (including nested imports) and self time (excluding nested imports). Note that its output may be broken in multi-threaded diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 943bee6..4dcfde4 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3589,16 +3589,6 @@ slot_tp_del(PyObject *self) /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so * we need to undo that. */ _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --Py_TYPE(self)->tp_frees; - --Py_TYPE(self)->tp_allocs; -#endif } static PyObject * diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 5fd92f7..00151b8 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -18,10 +18,6 @@ class bytes "PyBytesObject *" "&PyBytes_Type" #include "clinic/bytesobject.c.h" -#ifdef COUNT_ALLOCS -Py_ssize_t _Py_null_strings, _Py_one_strings; -#endif - static PyBytesObject *characters[UCHAR_MAX + 1]; static PyBytesObject *nullstring; @@ -68,9 +64,6 @@ _PyBytes_FromSize(Py_ssize_t size, int use_calloc) assert(size >= 0); if (size == 0 && (op = nullstring) != NULL) { -#ifdef COUNT_ALLOCS - _Py_null_strings++; -#endif Py_INCREF(op); return (PyObject *)op; } @@ -112,9 +105,6 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size) if (size == 1 && str != NULL && (op = characters[*str & UCHAR_MAX]) != NULL) { -#ifdef COUNT_ALLOCS - _Py_one_strings++; -#endif Py_INCREF(op); return (PyObject *)op; } @@ -148,16 +138,10 @@ PyBytes_FromString(const char *str) return NULL; } if (size == 0 && (op = nullstring) != NULL) { -#ifdef COUNT_ALLOCS - _Py_null_strings++; -#endif Py_INCREF(op); return (PyObject *)op; } if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) { -#ifdef COUNT_ALLOCS - _Py_one_strings++; -#endif Py_INCREF(op); return (PyObject *)op; } diff --git a/Objects/listobject.c b/Objects/listobject.c index 2c07ceb..c93a0fe 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -94,29 +94,6 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) return 0; } -/* Debug statistic to compare allocations with reuse through the free list */ -#undef SHOW_ALLOC_COUNT -#ifdef SHOW_ALLOC_COUNT -static size_t count_alloc = 0; -static size_t count_reuse = 0; - -static void -show_alloc(void) -{ - PyInterpreterState *interp = _PyInterpreterState_Get(); - if (!interp->config.show_alloc_count) { - return; - } - - fprintf(stderr, "List allocations: %" PY_FORMAT_SIZE_T "d\n", - count_alloc); - fprintf(stderr, "List reuse through freelist: %" PY_FORMAT_SIZE_T - "d\n", count_reuse); - fprintf(stderr, "%.2f%% reuse rate\n\n", - (100.0*count_reuse/(count_alloc+count_reuse))); -} -#endif - /* Empty list reuse scheme to save calls to malloc and free */ #ifndef PyList_MAXFREELIST #define PyList_MAXFREELIST 80 @@ -156,13 +133,6 @@ PyObject * PyList_New(Py_ssize_t size) { PyListObject *op; -#ifdef SHOW_ALLOC_COUNT - static int initialized = 0; - if (!initialized) { - Py_AtExit(show_alloc); - initialized = 1; - } -#endif if (size < 0) { PyErr_BadInternalCall(); @@ -172,16 +142,10 @@ PyList_New(Py_ssize_t size) numfree--; op = free_list[numfree]; _Py_NewReference((PyObject *)op); -#ifdef SHOW_ALLOC_COUNT - count_reuse++; -#endif } else { op = PyObject_GC_New(PyListObject, &PyList_Type); if (op == NULL) return NULL; -#ifdef SHOW_ALLOC_COUNT - count_alloc++; -#endif } if (size <= 0) op->ob_item = NULL; diff --git a/Objects/longobject.c b/Objects/longobject.c index 124b837..9115fa1 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -35,10 +35,6 @@ PyObject *_PyLong_One = NULL; #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) -#ifdef COUNT_ALLOCS -Py_ssize_t _Py_quick_int_allocs, _Py_quick_neg_int_allocs; -#endif - static PyObject * get_small_int(sdigit ival) { @@ -46,12 +42,6 @@ get_small_int(sdigit ival) PyThreadState *tstate = _PyThreadState_GET(); PyObject *v = (PyObject*)tstate->interp->small_ints[ival + NSMALLNEGINTS]; Py_INCREF(v); -#ifdef COUNT_ALLOCS - if (ival >= 0) - _Py_quick_int_allocs++; - else - _Py_quick_neg_int_allocs++; -#endif return v; } diff --git a/Objects/object.c b/Objects/object.c index 67a6386..2154d11 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -113,120 +113,6 @@ _Py_AddToAllObjects(PyObject *op, int force) } #endif /* Py_TRACE_REFS */ -#ifdef COUNT_ALLOCS -static PyTypeObject *type_list; -/* All types are added to type_list, at least when - they get one object created. That makes them - immortal, which unfortunately contributes to - garbage itself. If unlist_types_without_objects - is set, they will be removed from the type_list - once the last object is deallocated. */ -static int unlist_types_without_objects; -extern Py_ssize_t _Py_tuple_zero_allocs, _Py_fast_tuple_allocs; -extern Py_ssize_t _Py_quick_int_allocs, _Py_quick_neg_int_allocs; -extern Py_ssize_t _Py_null_strings, _Py_one_strings; -void -_Py_dump_counts(FILE* f) -{ - PyInterpreterState *interp = _PyInterpreterState_Get(); - if (!interp->config.show_alloc_count) { - return; - } - - PyTypeObject *tp; - for (tp = type_list; tp; tp = tp->tp_next) - fprintf(f, "%s alloc'd: %" PY_FORMAT_SIZE_T "d, " - "freed: %" PY_FORMAT_SIZE_T "d, " - "max in use: %" PY_FORMAT_SIZE_T "d\n", - tp->tp_name, tp->tp_allocs, tp->tp_frees, - tp->tp_maxalloc); - fprintf(f, "fast tuple allocs: %" PY_FORMAT_SIZE_T "d, " - "empty: %" PY_FORMAT_SIZE_T "d\n", - _Py_fast_tuple_allocs, _Py_tuple_zero_allocs); - fprintf(f, "fast int allocs: pos: %" PY_FORMAT_SIZE_T "d, " - "neg: %" PY_FORMAT_SIZE_T "d\n", - _Py_quick_int_allocs, _Py_quick_neg_int_allocs); - fprintf(f, "null strings: %" PY_FORMAT_SIZE_T "d, " - "1-strings: %" PY_FORMAT_SIZE_T "d\n", - _Py_null_strings, _Py_one_strings); -} - -PyObject * -_Py_get_counts(void) -{ - PyTypeObject *tp; - PyObject *result; - PyObject *v; - - result = PyList_New(0); - if (result == NULL) - return NULL; - for (tp = type_list; tp; tp = tp->tp_next) { - v = Py_BuildValue("(snnn)", tp->tp_name, tp->tp_allocs, - tp->tp_frees, tp->tp_maxalloc); - if (v == NULL) { - Py_DECREF(result); - return NULL; - } - if (PyList_Append(result, v) < 0) { - Py_DECREF(v); - Py_DECREF(result); - return NULL; - } - Py_DECREF(v); - } - return result; -} - -void -_Py_inc_count(PyTypeObject *tp) -{ - if (tp->tp_next == NULL && tp->tp_prev == NULL) { - /* first time; insert in linked list */ - if (type_list) - type_list->tp_prev = tp; - tp->tp_next = type_list; - /* Note that as of Python 2.2, heap-allocated type objects - * can go away, but this code requires that they stay alive - * until program exit. That's why we're careful with - * refcounts here. type_list gets a new reference to tp, - * while ownership of the reference type_list used to hold - * (if any) was transferred to tp->tp_next in the line above. - * tp is thus effectively immortal after this. - */ - Py_INCREF(tp); - type_list = tp; -#ifdef Py_TRACE_REFS - /* Also insert in the doubly-linked list of all objects, - * if not already there. - */ - _Py_AddToAllObjects((PyObject *)tp, 0); -#endif - } - tp->tp_allocs++; - if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc) - tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees; -} - -void _Py_dec_count(PyTypeObject *tp) -{ - tp->tp_frees++; - if (unlist_types_without_objects && - tp->tp_allocs == tp->tp_frees) { - /* unlink the type from type_list */ - if (tp->tp_prev) - tp->tp_prev->tp_next = tp->tp_next; - else - type_list = tp->tp_next; - if (tp->tp_next) - tp->tp_next->tp_prev = tp->tp_prev; - tp->tp_next = tp->tp_prev = NULL; - Py_DECREF(tp); - } -} - -#endif - #ifdef Py_REF_DEBUG /* Log a fatal error; doesn't return. */ void @@ -349,15 +235,6 @@ PyObject_CallFinalizerFromDealloc(PyObject *self) /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so * we need to undo that. */ _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. */ -#ifdef COUNT_ALLOCS - --Py_TYPE(self)->tp_frees; - --Py_TYPE(self)->tp_allocs; -#endif return -1; } @@ -1970,7 +1847,6 @@ _Py_ForgetReference(PyObject *op) op->_ob_next->_ob_prev = op->_ob_prev; op->_ob_prev->_ob_next = op->_ob_next; op->_ob_next = op->_ob_prev = NULL; - _Py_INC_TPFREES(op); } /* Print all live objects. Because PyObject_Print is called, the @@ -2289,8 +2165,6 @@ _Py_Dealloc(PyObject *op) destructor dealloc = Py_TYPE(op)->tp_dealloc; #ifdef Py_TRACE_REFS _Py_ForgetReference(op); -#else - _Py_INC_TPFREES(op); #endif (*dealloc)(op); } diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 08f7022..2708b9a 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -28,43 +28,10 @@ class tuple "PyTupleObject *" "&PyTuple_Type" static PyTupleObject *free_list[PyTuple_MAXSAVESIZE]; static int numfree[PyTuple_MAXSAVESIZE]; #endif -#ifdef COUNT_ALLOCS -Py_ssize_t _Py_fast_tuple_allocs; -Py_ssize_t _Py_tuple_zero_allocs; -#endif - -/* Debug statistic to count GC tracking of tuples. - Please note that tuples are only untracked when considered by the GC, and - many of them will be dead before. Therefore, a tracking rate close to 100% - does not necessarily prove that the heuristic is inefficient. -*/ -#ifdef SHOW_TRACK_COUNT -static Py_ssize_t count_untracked = 0; -static Py_ssize_t count_tracked = 0; - -static void -show_track(void) -{ - PyInterpreterState *interp = _PyInterpreterState_Get(); - if (!interp->config.show_alloc_count) { - return; - } - - fprintf(stderr, "Tuples created: %" PY_FORMAT_SIZE_T "d\n", - count_tracked + count_untracked); - fprintf(stderr, "Tuples tracked by the GC: %" PY_FORMAT_SIZE_T - "d\n", count_tracked); - fprintf(stderr, "%.2f%% tuple tracking rate\n\n", - (100.0*count_tracked/(count_untracked+count_tracked))); -} -#endif static inline void tuple_gc_track(PyTupleObject *op) { -#ifdef SHOW_TRACK_COUNT - count_tracked++; -#endif _PyObject_GC_TRACK(op); } @@ -106,9 +73,6 @@ tuple_alloc(Py_ssize_t size) assert(size != 0); free_list[size] = (PyTupleObject *) op->ob_item[0]; numfree[size]--; -#ifdef COUNT_ALLOCS - _Py_fast_tuple_allocs++; -#endif /* Inline PyObject_InitVar */ #ifdef Py_TRACE_REFS Py_SIZE(op) = size; @@ -139,9 +103,6 @@ PyTuple_New(Py_ssize_t size) if (size == 0 && free_list[0]) { op = free_list[0]; Py_INCREF(op); -#ifdef COUNT_ALLOCS - _Py_tuple_zero_allocs++; -#endif return (PyObject *) op; } #endif @@ -227,10 +188,6 @@ _PyTuple_MaybeUntrack(PyObject *op) _PyObject_GC_MAY_BE_TRACKED(elt)) return; } -#ifdef SHOW_TRACK_COUNT - count_tracked--; - count_untracked++; -#endif _PyObject_GC_UNTRACK(op); } @@ -1001,9 +958,6 @@ _PyTuple_Fini(void) (void)PyTuple_ClearFreeList(); #endif -#ifdef SHOW_TRACK_COUNT - show_track(); -#endif } /*********************** Tuple Iterator **************************/ diff --git a/Programs/_testembed.c b/Programs/_testembed.c index b98a38a..b98696c 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -506,7 +506,6 @@ static int test_init_from_config(void) config.import_time = 1; config.show_ref_count = 1; - config.show_alloc_count = 1; /* FIXME: test dump_refs: bpo-34223 */ putenv("PYTHONMALLOCSTATS=0"); diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index daca0e6..4615eba 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -758,27 +758,6 @@ exit: return return_value; } -#if defined(COUNT_ALLOCS) - -PyDoc_STRVAR(sys_getcounts__doc__, -"getcounts($module, /)\n" -"--\n" -"\n"); - -#define SYS_GETCOUNTS_METHODDEF \ - {"getcounts", (PyCFunction)sys_getcounts, METH_NOARGS, sys_getcounts__doc__}, - -static PyObject * -sys_getcounts_impl(PyObject *module); - -static PyObject * -sys_getcounts(PyObject *module, PyObject *Py_UNUSED(ignored)) -{ - return sys_getcounts_impl(module); -} - -#endif /* defined(COUNT_ALLOCS) */ - PyDoc_STRVAR(sys__getframe__doc__, "_getframe($module, depth=0, /)\n" "--\n" @@ -988,11 +967,7 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #define SYS_GETTOTALREFCOUNT_METHODDEF #endif /* !defined(SYS_GETTOTALREFCOUNT_METHODDEF) */ -#ifndef SYS_GETCOUNTS_METHODDEF - #define SYS_GETCOUNTS_METHODDEF -#endif /* !defined(SYS_GETCOUNTS_METHODDEF) */ - #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=decd687b7631de4b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=39eb34a01fb9a919 input=a9049054013a1b77]*/ diff --git a/Python/initconfig.c b/Python/initconfig.c index 9a784c7..493b4bb 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -73,9 +73,6 @@ static const char usage_3[] = "\ tracemalloc module. By default, only the most recent frame is stored in a\n\ traceback of a trace. Use -X tracemalloc=NFRAME to start tracing with a\n\ traceback limit of NFRAME frames\n\ - -X showalloccount: output the total count of allocated objects for each\n\ - type when the program finishes. This only works when Python was built with\n\ - COUNT_ALLOCS defined\n\ -X importtime: show how long each import takes. It shows module name,\n\ cumulative time (including nested imports) and self time (excluding\n\ nested imports). Note that its output may be broken in multi-threaded\n\ @@ -800,7 +797,6 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2) COPY_ATTR(tracemalloc); COPY_ATTR(import_time); COPY_ATTR(show_ref_count); - COPY_ATTR(show_alloc_count); COPY_ATTR(dump_refs); COPY_ATTR(malloc_stats); @@ -903,7 +899,6 @@ config_as_dict(const PyConfig *config) SET_ITEM_INT(tracemalloc); SET_ITEM_INT(import_time); SET_ITEM_INT(show_ref_count); - SET_ITEM_INT(show_alloc_count); SET_ITEM_INT(dump_refs); SET_ITEM_INT(malloc_stats); SET_ITEM_WSTR(filesystem_encoding); @@ -1691,9 +1686,6 @@ config_read(PyConfig *config) if (config_get_xoption(config, L"showrefcount")) { config->show_ref_count = 1; } - if (config_get_xoption(config, L"showalloccount")) { - config->show_alloc_count = 1; - } status = config_read_complex_options(config); if (_PyStatus_EXCEPTION(status)) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d5d60d0..f130735 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1173,10 +1173,6 @@ Py_Initialize(void) } -#ifdef COUNT_ALLOCS -extern void _Py_dump_counts(FILE*); -#endif - /* Flush stdout and stderr */ static int @@ -1393,13 +1389,6 @@ Py_FinalizeEx(void) * XXX I haven't seen a real-life report of either of these. */ _PyGC_CollectIfEnabled(); -#ifdef COUNT_ALLOCS - /* With COUNT_ALLOCS, it helps to run GC multiple times: - each collection might release some types from the type - list, so they become garbage. */ - while (_PyGC_CollectIfEnabled() > 0) - /* nothing */; -#endif /* Clear all loghooks */ /* We want minimal exposure of this function, so define the extern @@ -1451,10 +1440,6 @@ Py_FinalizeEx(void) /* unload faulthandler module */ _PyFaulthandler_Fini(); - /* Debugging stuff */ -#ifdef COUNT_ALLOCS - _Py_dump_counts(stderr); -#endif /* dump hash stats */ _PyHash_Fini(); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 17e7960..1cb1030 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1685,20 +1685,6 @@ sys_getallocatedblocks_impl(PyObject *module) return _Py_GetAllocatedBlocks(); } -#ifdef COUNT_ALLOCS -/*[clinic input] -sys.getcounts -[clinic start generated code]*/ - -static PyObject * -sys_getcounts_impl(PyObject *module) -/*[clinic end generated code: output=20df00bc164f43cb input=ad2ec7bda5424953]*/ -{ - extern PyObject *_Py_get_counts(void); - - return _Py_get_counts(); -} -#endif /*[clinic input] sys._getframe @@ -1879,7 +1865,6 @@ static PyMethodDef sys_methods[] = { SYS_GETDEFAULTENCODING_METHODDEF SYS_GETDLOPENFLAGS_METHODDEF SYS_GETALLOCATEDBLOCKS_METHODDEF - SYS_GETCOUNTS_METHODDEF #ifdef DYNAMIC_EXECUTION_PROFILE {"getdxp", _Py_GetDXProfile, METH_VARARGS}, #endif |