summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/init_config.rst12
-rw-r--r--Doc/c-api/typeobj.rst34
-rw-r--r--Doc/using/cmdline.rst5
-rw-r--r--Doc/whatsnew/3.9.rst9
-rw-r--r--Include/cpython/initconfig.h1
-rw-r--r--Include/cpython/object.h11
-rw-r--r--Include/object.h20
-rw-r--r--Lib/subprocess.py2
-rw-r--r--Lib/test/support/__init__.py3
-rw-r--r--Lib/test/test_embed.py2
-rw-r--r--Lib/test/test_gc.py6
-rw-r--r--Lib/test/test_io.py2
-rw-r--r--Lib/test/test_logging.py1
-rw-r--r--Lib/test/test_module.py4
-rw-r--r--Lib/test/test_support.py1
-rw-r--r--Lib/test/test_sys.py4
-rw-r--r--Lib/test/test_threading.py5
-rw-r--r--Lib/test/test_traceback.py1
-rw-r--r--Lib/test/test_warnings/__init__.py1
-rw-r--r--Lib/test/test_weakref.py1
-rw-r--r--Misc/NEWS.d/next/Build/2020-01-29-19-17-02.bpo-39489.HKPzv-.rst1
-rw-r--r--Misc/SpecialBuilds.txt53
-rw-r--r--Misc/python.man4
-rw-r--r--Modules/_testcapimodule.c10
-rw-r--r--Objects/bytesobject.c16
-rw-r--r--Objects/listobject.c36
-rw-r--r--Objects/longobject.c10
-rw-r--r--Objects/object.c126
-rw-r--r--Objects/tupleobject.c46
-rw-r--r--Programs/_testembed.c1
-rw-r--r--Python/clinic/sysmodule.c.h27
-rw-r--r--Python/initconfig.c8
-rw-r--r--Python/pylifecycle.c15
-rw-r--r--Python/sysmodule.c15
34 files changed, 24 insertions, 469 deletions
diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index 108bd2c024..c589a6fe3f 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 7b205c0449..a8a779ef61 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 fb88673d30..2206e5065b 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 931f8bf13f..3b7a9d105d 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 54e662347e..c5fa2b3857 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 dc8fd6fa89..5fcad55c5c 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 7a5f57357b..1a2e704e93 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 26a1e69bd3..c8db387091 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 215bab8131..259c7069bf 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 73ef96265b..87842b9377 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 18f8d10c5b..acb6391944 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 501e931396..8a123fa1dc 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 c38fdae033..e223522cc7 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 efe9a8ed5e..1d44563579 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 2f347bd540..175f7c845f 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 947c935f34..58701a11f9 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 62f2d54ad0..a9d31afbe3 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 7135d997d5..60e0b58275 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 c6fb097ae6..268ecb03f4 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 228bc17b23..63c725527d 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 0000000000..652a4356e2
--- /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 d1a032165f..27369abfb3 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 3645b0206e..89a15a5e7b 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 943bee6e21..4dcfde4543 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 5fd92f72a5..00151b8256 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 2c07ceb0d4..c93a0feaf3 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 124b837d00..9115fa184f 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 67a6386e2a..2154d119a0 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 08f7022fda..2708b9aad3 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 b98a38a1ba..b98696cbe0 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 daca0e6411..4615ebaab5 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 9a784c7511..493b4bb440 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 d5d60d0a6d..f1307356a7 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 17e79603c2..1cb10300d7 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