bpo-39489: Remove COUNT_ALLOCS special build (GH-18259)

Remove:

* COUNT_ALLOCS macro
* sys.getcounts() function
* SHOW_ALLOC_COUNT code in listobject.c
* SHOW_TRACK_COUNT code in tupleobject.c
* PyConfig.show_alloc_count field
* -X showalloccount command line option
* @test.support.requires_type_collecting decorator
This commit is contained in:
Victor Stinner 2020-02-03 15:17:15 +01:00 committed by GitHub
parent 869c0c99b9
commit c6e5c1123b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 24 additions and 469 deletions

View File

@ -627,14 +627,6 @@ PyConfig
``python3 -m MODULE`` argument. Used by :c:func:`Py_RunMain`. ``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 .. c:member:: int show_ref_count
Show total reference count at exit? 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` The ``xoptions`` options are parsed to set other options: see :option:`-X`
option. option.
.. versionchanged:: 3.9
The ``show_alloc_count`` field has been removed.
Initialization with PyConfig Initialization with PyConfig
---------------------------- ----------------------------

View File

@ -148,15 +148,6 @@ Quick Reference
| :c:member:`~PyTypeObject.tp_vectorcall` | :c:type:`vectorcallfunc` | | | | | | | :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] .. [#slots]
A slot name in parentheses indicates it is (effectively) deprecated. A slot name in parentheses indicates it is (effectively) deprecated.
Names in angle brackets should be treated as read-only. 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) .. 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 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 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 becomes part of a refcount cycle, that cycle might be collected by a garbage

View File

@ -434,9 +434,6 @@ Miscellaneous options
stored in a traceback of a trace. Use ``-X tracemalloc=NFRAME`` to start stored in a traceback of a trace. Use ``-X tracemalloc=NFRAME`` to start
tracing with a traceback limit of *NFRAME* frames. See the tracing with a traceback limit of *NFRAME* frames. See the
:func:`tracemalloc.start` for more information. :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 * ``-X importtime`` to show how long each import takes. It shows module
name, cumulative time (including nested imports) and self time (excluding name, cumulative time (including nested imports) and self time (excluding
nested imports). Note that its output may be broken in multi-threaded 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 Using ``-X dev`` option, check *encoding* and *errors* arguments on
string encoding and decoding operations. string encoding and decoding operations.
The ``-X showalloccount`` option has been removed.
Options you shouldn't use Options you shouldn't use
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -348,6 +348,9 @@ Build and C API Changes
functions are now required to build Python. functions are now required to build Python.
(Contributed by Victor Stinner in :issue:`39395`.) (Contributed by Victor Stinner in :issue:`39395`.)
* The ``COUNT_ALLOCS`` special build macro has been removed.
(Contributed by Victor Stinner in :issue:`39489`.)
Deprecated Deprecated
========== ==========
@ -484,6 +487,12 @@ Removed
``asyncio.Condition`` and ``asyncio.Semaphore``. ``asyncio.Condition`` and ``asyncio.Semaphore``.
(Contributed by Andrew Svetlov in :issue:`34793`.) (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 Porting to Python 3.9
===================== =====================

View File

@ -153,7 +153,6 @@ typedef struct {
int import_time; /* PYTHONPROFILEIMPORTTIME, -X importtime */ int import_time; /* PYTHONPROFILEIMPORTTIME, -X importtime */
int show_ref_count; /* -X showrefcount */ int show_ref_count; /* -X showrefcount */
int show_alloc_count; /* -X showalloccount */
int dump_refs; /* PYTHONDUMPREFS */ int dump_refs; /* PYTHONDUMPREFS */
int malloc_stats; /* PYTHONMALLOCSTATS */ int malloc_stats; /* PYTHONMALLOCSTATS */

View File

@ -255,15 +255,6 @@ typedef struct _typeobject {
destructor tp_finalize; destructor tp_finalize;
vectorcallfunc tp_vectorcall; 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; } PyTypeObject;
/* The *real* layout of a type object when allocated on the heap */ /* 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; destructor dealloc = Py_TYPE(op)->tp_dealloc;
#ifdef Py_TRACE_REFS #ifdef Py_TRACE_REFS
_Py_ForgetReference(op); _Py_ForgetReference(op);
#else
_Py_INC_TPFREES(op);
#endif #endif
(*dealloc)(op); (*dealloc)(op);
} }

View File

@ -405,20 +405,6 @@ PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void);
#define _Py_DEC_REFTOTAL #define _Py_DEC_REFTOTAL
#endif /* Py_REF_DEBUG */ #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 /* Update the Python traceback of an object. This function must be called
when a memory block is reused from a free list. */ when a memory block is reused from a free list. */
PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op); PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op);
@ -438,15 +424,13 @@ static inline void _Py_NewReference(PyObject *op)
if (_Py_tracemalloc_config.tracing) { if (_Py_tracemalloc_config.tracing) {
_PyTraceMalloc_NewReference(op); _PyTraceMalloc_NewReference(op);
} }
_Py_INC_TPALLOCS(op);
_Py_INC_REFTOTAL; _Py_INC_REFTOTAL;
Py_REFCNT(op) = 1; 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 */ /* nothing to do */
_Py_INC_TPFREES(op);
} }
#endif /* !Py_TRACE_REFS */ #endif /* !Py_TRACE_REFS */

View File

@ -325,7 +325,7 @@ def _args_from_interpreter_flags():
if dev_mode: if dev_mode:
args.extend(('-X', 'dev')) args.extend(('-X', 'dev'))
for opt in ('faulthandler', 'tracemalloc', 'importtime', for opt in ('faulthandler', 'tracemalloc', 'importtime',
'showalloccount', 'showrefcount', 'utf8'): 'showrefcount', 'utf8'):
if opt in xoptions: if opt in xoptions:
value = xoptions[opt] value = xoptions[opt]
if value is True: if value is True:

View File

@ -2512,9 +2512,6 @@ def swap_item(obj, item, new_val):
if item in obj: if item in obj:
del obj[item] del obj[item]
requires_type_collecting = unittest.skipIf(hasattr(sys, 'getcounts'),
'types are immortal if COUNT_ALLOCS is defined')
def args_from_interpreter_flags(): def args_from_interpreter_flags():
"""Return a list of command-line arguments reproducing the current """Return a list of command-line arguments reproducing the current
settings in sys.flags and sys.warnoptions.""" settings in sys.flags and sys.warnoptions."""

View File

@ -356,7 +356,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'tracemalloc': 0, 'tracemalloc': 0,
'import_time': 0, 'import_time': 0,
'show_ref_count': 0, 'show_ref_count': 0,
'show_alloc_count': 0,
'dump_refs': 0, 'dump_refs': 0,
'malloc_stats': 0, 'malloc_stats': 0,
@ -729,7 +728,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'tracemalloc': 2, 'tracemalloc': 2,
'import_time': 1, 'import_time': 1,
'show_ref_count': 1, 'show_ref_count': 1,
'show_alloc_count': 1,
'malloc_stats': 1, 'malloc_stats': 1,
'stdio_encoding': 'iso8859-1', 'stdio_encoding': 'iso8859-1',

View File

@ -2,7 +2,7 @@ import unittest
import unittest.mock import unittest.mock
from test.support import (verbose, refcount_test, run_unittest, from test.support import (verbose, refcount_test, run_unittest,
cpython_only, start_threads, cpython_only, start_threads,
temp_dir, requires_type_collecting, TESTFN, unlink, temp_dir, TESTFN, unlink,
import_module) import_module)
from test.support.script_helper import assert_python_ok, make_script from test.support.script_helper import assert_python_ok, make_script
@ -131,7 +131,6 @@ class GCTests(unittest.TestCase):
del a del a
self.assertNotEqual(gc.collect(), 0) self.assertNotEqual(gc.collect(), 0)
@requires_type_collecting
def test_newinstance(self): def test_newinstance(self):
class A(object): class A(object):
pass pass
@ -709,7 +708,6 @@ class GCTests(unittest.TestCase):
stderr = run_command(code % "gc.DEBUG_SAVEALL") stderr = run_command(code % "gc.DEBUG_SAVEALL")
self.assertNotIn(b"uncollectable objects at shutdown", stderr) self.assertNotIn(b"uncollectable objects at shutdown", stderr)
@requires_type_collecting
def test_gc_main_module_at_shutdown(self): def test_gc_main_module_at_shutdown(self):
# Create a reference cycle through the __main__ module and check # Create a reference cycle through the __main__ module and check
# it gets collected at interpreter shutdown. # it gets collected at interpreter shutdown.
@ -723,7 +721,6 @@ class GCTests(unittest.TestCase):
rc, out, err = assert_python_ok('-c', code) rc, out, err = assert_python_ok('-c', code)
self.assertEqual(out.strip(), b'__del__ called') self.assertEqual(out.strip(), b'__del__ called')
@requires_type_collecting
def test_gc_ordinary_module_at_shutdown(self): def test_gc_ordinary_module_at_shutdown(self):
# Same as above, but with a non-__main__ module. # Same as above, but with a non-__main__ module.
with temp_dir() as script_dir: with temp_dir() as script_dir:
@ -743,7 +740,6 @@ class GCTests(unittest.TestCase):
rc, out, err = assert_python_ok('-c', code) rc, out, err = assert_python_ok('-c', code)
self.assertEqual(out.strip(), b'__del__ called') self.assertEqual(out.strip(), b'__del__ called')
@requires_type_collecting
def test_global_del_SystemExit(self): def test_global_del_SystemExit(self):
code = """if 1: code = """if 1:
class ClassWithDel: class ClassWithDel:

View File

@ -3492,7 +3492,6 @@ class TextIOWrapperTest(unittest.TestCase):
""".format(iomod=iomod, kwargs=kwargs) """.format(iomod=iomod, kwargs=kwargs)
return assert_python_ok("-c", code) return assert_python_ok("-c", code)
@support.requires_type_collecting
def test_create_at_shutdown_without_encoding(self): def test_create_at_shutdown_without_encoding(self):
rc, out, err = self._check_create_at_shutdown() rc, out, err = self._check_create_at_shutdown()
if err: if err:
@ -3502,7 +3501,6 @@ class TextIOWrapperTest(unittest.TestCase):
else: else:
self.assertEqual("ok", out.decode().strip()) self.assertEqual("ok", out.decode().strip())
@support.requires_type_collecting
def test_create_at_shutdown_with_encoding(self): def test_create_at_shutdown_with_encoding(self):
rc, out, err = self._check_create_at_shutdown(encoding='utf-8', rc, out, err = self._check_create_at_shutdown(encoding='utf-8',
errors='strict') errors='strict')

View File

@ -4252,7 +4252,6 @@ class ModuleLevelMiscTest(BaseTest):
h.close() h.close()
logging.setLoggerClass(logging.Logger) logging.setLoggerClass(logging.Logger)
@support.requires_type_collecting
def test_logging_at_shutdown(self): def test_logging_at_shutdown(self):
# Issue #20037 # Issue #20037
code = """if 1: code = """if 1:

View File

@ -1,7 +1,7 @@
# Test the module type # Test the module type
import unittest import unittest
import weakref 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 from test.support.script_helper import assert_python_ok
import sys import sys
@ -101,7 +101,6 @@ class ModuleTests(unittest.TestCase):
gc_collect() gc_collect()
self.assertEqual(f().__dict__["bar"], 4) self.assertEqual(f().__dict__["bar"], 4)
@requires_type_collecting
def test_clear_dict_in_ref_cycle(self): def test_clear_dict_in_ref_cycle(self):
destroyed = [] destroyed = []
m = ModuleType("foo") m = ModuleType("foo")
@ -266,7 +265,6 @@ a = A(destroyed)"""
self.assertEqual(r[-len(ends_with):], ends_with, self.assertEqual(r[-len(ends_with):], ends_with,
'{!r} does not end with {!r}'.format(r, ends_with)) '{!r} does not end with {!r}'.format(r, ends_with))
@requires_type_collecting
def test_module_finalization_at_shutdown(self): def test_module_finalization_at_shutdown(self):
# Module globals and builtins should still be available during shutdown # Module globals and builtins should still be available during shutdown
rc, out, err = assert_python_ok("-c", "from test import final_a") rc, out, err = assert_python_ok("-c", "from test import final_a")

View File

@ -493,7 +493,6 @@ class TestSupport(unittest.TestCase):
['-Wignore', '-X', 'dev'], ['-Wignore', '-X', 'dev'],
['-X', 'faulthandler'], ['-X', 'faulthandler'],
['-X', 'importtime'], ['-X', 'importtime'],
['-X', 'showalloccount'],
['-X', 'showrefcount'], ['-X', 'showrefcount'],
['-X', 'tracemalloc'], ['-X', 'tracemalloc'],
['-X', 'tracemalloc=3'], ['-X', 'tracemalloc=3'],

View File

@ -819,7 +819,6 @@ class SysModuleTest(unittest.TestCase):
c = sys.getallocatedblocks() c = sys.getallocatedblocks()
self.assertIn(c, range(b - 50, b + 50)) self.assertIn(c, range(b - 50, b + 50))
@test.support.requires_type_collecting
def test_is_finalizing(self): def test_is_finalizing(self):
self.assertIs(sys.is_finalizing(), False) self.assertIs(sys.is_finalizing(), False)
# Don't use the atexit module because _Py_Finalizing is only set # 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) rc, stdout, stderr = assert_python_ok('-c', code)
self.assertEqual(stdout.rstrip(), b'True') self.assertEqual(stdout.rstrip(), b'True')
@test.support.requires_type_collecting
def test_issue20602(self): def test_issue20602(self):
# sys.flags and sys.float_info were wiped during shutdown. # sys.flags and sys.float_info were wiped during shutdown.
code = """if 1: code = """if 1:
@ -1295,8 +1293,6 @@ class SizeofTest(unittest.TestCase):
# type # type
# static type: PyTypeObject # static type: PyTypeObject
fmt = 'P2nPI13Pl4Pn9Pn11PIPP' fmt = 'P2nPI13Pl4Pn9Pn11PIPP'
if hasattr(sys, 'getcounts'):
fmt += '3n2P'
s = vsize(fmt) s = vsize(fmt)
check(int, s) check(int, s)
# class # class

View File

@ -3,8 +3,7 @@ Tests for the threading module.
""" """
import test.support import test.support
from test.support import (verbose, import_module, cpython_only, from test.support import verbose, import_module, cpython_only
requires_type_collecting)
from test.support.script_helper import assert_python_ok, assert_python_failure from test.support.script_helper import assert_python_ok, assert_python_failure
import random import random
@ -552,7 +551,6 @@ class ThreadTests(BaseTestCase):
self.assertEqual(err, b"") self.assertEqual(err, b"")
self.assertEqual(data, "Thread-1\nTrue\nTrue\n") self.assertEqual(data, "Thread-1\nTrue\nTrue\n")
@requires_type_collecting
def test_main_thread_during_shutdown(self): def test_main_thread_during_shutdown(self):
# bpo-31516: current_thread() should still point to the main thread # bpo-31516: current_thread() should still point to the main thread
# at shutdown # at shutdown
@ -1113,7 +1111,6 @@ class ThreadingExceptionTests(BaseTestCase):
self.assertIn("ZeroDivisionError", err) self.assertIn("ZeroDivisionError", err)
self.assertNotIn("Unhandled exception", err) self.assertNotIn("Unhandled exception", err)
@requires_type_collecting
def test_print_exception_stderr_is_none_1(self): def test_print_exception_stderr_is_none_1(self):
script = r"""if True: script = r"""if True:
import sys import sys

View File

@ -174,7 +174,6 @@ class TracebackCases(unittest.TestCase):
# Issue #18960: coding spec should have no effect # Issue #18960: coding spec should have no effect
do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5) 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): def test_print_traceback_at_exit(self):
# Issue #22599: Ensure that it is possible to use the traceback module # Issue #22599: Ensure that it is possible to use the traceback module
# to display an exception at Python exit # to display an exception at Python exit

View File

@ -1227,7 +1227,6 @@ class BootstrapTest(unittest.TestCase):
class FinalizationTest(unittest.TestCase): class FinalizationTest(unittest.TestCase):
@support.requires_type_collecting
def test_finalization(self): def test_finalization(self):
# Issue #19421: warnings.warn() should not crash # Issue #19421: warnings.warn() should not crash
# during Python finalization # during Python finalization

View File

@ -649,7 +649,6 @@ class ReferencesTestCase(TestBase):
del c1, c2, C, D del c1, c2, C, D
gc.collect() gc.collect()
@support.requires_type_collecting
def test_callback_in_cycle_resurrection(self): def test_callback_in_cycle_resurrection(self):
import gc import gc

View File

@ -0,0 +1 @@
Remove ``COUNT_ALLOCS`` special build.

View File

@ -46,9 +46,7 @@ Build option: ``./configure --with-trace-refs``.
Turn on heavy reference debugging. This is major surgery. Every PyObject grows 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 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 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, allocated.
a static type object T does appear in this list if at least one object of type T
has been created.
Note that because the fundamental PyObject layout changes, Python modules Note that because the fundamental PyObject layout changes, Python modules
compiled with Py_TRACE_REFS are incompatible with modules compiled without it. 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. "#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 LLTRACE
------- -------

View File

@ -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 of a trace. Use -X tracemalloc=NFRAME to start tracing with a
traceback limit of NFRAME frames 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, -X importtime: show how long each import takes. It shows module name,
cumulative time (including nested imports) and self time (excluding cumulative time (including nested imports) and self time (excluding
nested imports). Note that its output may be broken in multi-threaded nested imports). Note that its output may be broken in multi-threaded

View File

@ -3589,16 +3589,6 @@ slot_tp_del(PyObject *self)
/* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
* we need to undo that. */ * we need to undo that. */
_Py_DEC_REFTOTAL; _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 * static PyObject *

View File

@ -18,10 +18,6 @@ class bytes "PyBytesObject *" "&PyBytes_Type"
#include "clinic/bytesobject.c.h" #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 *characters[UCHAR_MAX + 1];
static PyBytesObject *nullstring; static PyBytesObject *nullstring;
@ -68,9 +64,6 @@ _PyBytes_FromSize(Py_ssize_t size, int use_calloc)
assert(size >= 0); assert(size >= 0);
if (size == 0 && (op = nullstring) != NULL) { if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
_Py_null_strings++;
#endif
Py_INCREF(op); Py_INCREF(op);
return (PyObject *)op; return (PyObject *)op;
} }
@ -112,9 +105,6 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
if (size == 1 && str != NULL && if (size == 1 && str != NULL &&
(op = characters[*str & UCHAR_MAX]) != NULL) (op = characters[*str & UCHAR_MAX]) != NULL)
{ {
#ifdef COUNT_ALLOCS
_Py_one_strings++;
#endif
Py_INCREF(op); Py_INCREF(op);
return (PyObject *)op; return (PyObject *)op;
} }
@ -148,16 +138,10 @@ PyBytes_FromString(const char *str)
return NULL; return NULL;
} }
if (size == 0 && (op = nullstring) != NULL) { if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
_Py_null_strings++;
#endif
Py_INCREF(op); Py_INCREF(op);
return (PyObject *)op; return (PyObject *)op;
} }
if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) { if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
#ifdef COUNT_ALLOCS
_Py_one_strings++;
#endif
Py_INCREF(op); Py_INCREF(op);
return (PyObject *)op; return (PyObject *)op;
} }

View File

@ -94,29 +94,6 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
return 0; 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 */ /* Empty list reuse scheme to save calls to malloc and free */
#ifndef PyList_MAXFREELIST #ifndef PyList_MAXFREELIST
#define PyList_MAXFREELIST 80 #define PyList_MAXFREELIST 80
@ -156,13 +133,6 @@ PyObject *
PyList_New(Py_ssize_t size) PyList_New(Py_ssize_t size)
{ {
PyListObject *op; PyListObject *op;
#ifdef SHOW_ALLOC_COUNT
static int initialized = 0;
if (!initialized) {
Py_AtExit(show_alloc);
initialized = 1;
}
#endif
if (size < 0) { if (size < 0) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
@ -172,16 +142,10 @@ PyList_New(Py_ssize_t size)
numfree--; numfree--;
op = free_list[numfree]; op = free_list[numfree];
_Py_NewReference((PyObject *)op); _Py_NewReference((PyObject *)op);
#ifdef SHOW_ALLOC_COUNT
count_reuse++;
#endif
} else { } else {
op = PyObject_GC_New(PyListObject, &PyList_Type); op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL) if (op == NULL)
return NULL; return NULL;
#ifdef SHOW_ALLOC_COUNT
count_alloc++;
#endif
} }
if (size <= 0) if (size <= 0)
op->ob_item = NULL; op->ob_item = NULL;

View File

@ -35,10 +35,6 @@ PyObject *_PyLong_One = NULL;
#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
#define IS_SMALL_UINT(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 * static PyObject *
get_small_int(sdigit ival) get_small_int(sdigit ival)
{ {
@ -46,12 +42,6 @@ get_small_int(sdigit ival)
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
PyObject *v = (PyObject*)tstate->interp->small_ints[ival + NSMALLNEGINTS]; PyObject *v = (PyObject*)tstate->interp->small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v); Py_INCREF(v);
#ifdef COUNT_ALLOCS
if (ival >= 0)
_Py_quick_int_allocs++;
else
_Py_quick_neg_int_allocs++;
#endif
return v; return v;
} }

View File

@ -113,120 +113,6 @@ _Py_AddToAllObjects(PyObject *op, int force)
} }
#endif /* Py_TRACE_REFS */ #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 #ifdef Py_REF_DEBUG
/* Log a fatal error; doesn't return. */ /* Log a fatal error; doesn't return. */
void void
@ -349,15 +235,6 @@ PyObject_CallFinalizerFromDealloc(PyObject *self)
/* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
* we need to undo that. */ * we need to undo that. */
_Py_DEC_REFTOTAL; _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; return -1;
} }
@ -1970,7 +1847,6 @@ _Py_ForgetReference(PyObject *op)
op->_ob_next->_ob_prev = op->_ob_prev; op->_ob_next->_ob_prev = op->_ob_prev;
op->_ob_prev->_ob_next = op->_ob_next; op->_ob_prev->_ob_next = op->_ob_next;
op->_ob_next = op->_ob_prev = NULL; op->_ob_next = op->_ob_prev = NULL;
_Py_INC_TPFREES(op);
} }
/* Print all live objects. Because PyObject_Print is called, the /* 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; destructor dealloc = Py_TYPE(op)->tp_dealloc;
#ifdef Py_TRACE_REFS #ifdef Py_TRACE_REFS
_Py_ForgetReference(op); _Py_ForgetReference(op);
#else
_Py_INC_TPFREES(op);
#endif #endif
(*dealloc)(op); (*dealloc)(op);
} }

View File

@ -28,43 +28,10 @@ class tuple "PyTupleObject *" "&PyTuple_Type"
static PyTupleObject *free_list[PyTuple_MAXSAVESIZE]; static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
static int numfree[PyTuple_MAXSAVESIZE]; static int numfree[PyTuple_MAXSAVESIZE];
#endif #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 static inline void
tuple_gc_track(PyTupleObject *op) tuple_gc_track(PyTupleObject *op)
{ {
#ifdef SHOW_TRACK_COUNT
count_tracked++;
#endif
_PyObject_GC_TRACK(op); _PyObject_GC_TRACK(op);
} }
@ -106,9 +73,6 @@ tuple_alloc(Py_ssize_t size)
assert(size != 0); assert(size != 0);
free_list[size] = (PyTupleObject *) op->ob_item[0]; free_list[size] = (PyTupleObject *) op->ob_item[0];
numfree[size]--; numfree[size]--;
#ifdef COUNT_ALLOCS
_Py_fast_tuple_allocs++;
#endif
/* Inline PyObject_InitVar */ /* Inline PyObject_InitVar */
#ifdef Py_TRACE_REFS #ifdef Py_TRACE_REFS
Py_SIZE(op) = size; Py_SIZE(op) = size;
@ -139,9 +103,6 @@ PyTuple_New(Py_ssize_t size)
if (size == 0 && free_list[0]) { if (size == 0 && free_list[0]) {
op = free_list[0]; op = free_list[0];
Py_INCREF(op); Py_INCREF(op);
#ifdef COUNT_ALLOCS
_Py_tuple_zero_allocs++;
#endif
return (PyObject *) op; return (PyObject *) op;
} }
#endif #endif
@ -227,10 +188,6 @@ _PyTuple_MaybeUntrack(PyObject *op)
_PyObject_GC_MAY_BE_TRACKED(elt)) _PyObject_GC_MAY_BE_TRACKED(elt))
return; return;
} }
#ifdef SHOW_TRACK_COUNT
count_tracked--;
count_untracked++;
#endif
_PyObject_GC_UNTRACK(op); _PyObject_GC_UNTRACK(op);
} }
@ -1001,9 +958,6 @@ _PyTuple_Fini(void)
(void)PyTuple_ClearFreeList(); (void)PyTuple_ClearFreeList();
#endif #endif
#ifdef SHOW_TRACK_COUNT
show_track();
#endif
} }
/*********************** Tuple Iterator **************************/ /*********************** Tuple Iterator **************************/

View File

@ -506,7 +506,6 @@ static int test_init_from_config(void)
config.import_time = 1; config.import_time = 1;
config.show_ref_count = 1; config.show_ref_count = 1;
config.show_alloc_count = 1;
/* FIXME: test dump_refs: bpo-34223 */ /* FIXME: test dump_refs: bpo-34223 */
putenv("PYTHONMALLOCSTATS=0"); putenv("PYTHONMALLOCSTATS=0");

View File

@ -758,27 +758,6 @@ exit:
return return_value; 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__, PyDoc_STRVAR(sys__getframe__doc__,
"_getframe($module, depth=0, /)\n" "_getframe($module, depth=0, /)\n"
"--\n" "--\n"
@ -988,11 +967,7 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored))
#define SYS_GETTOTALREFCOUNT_METHODDEF #define SYS_GETTOTALREFCOUNT_METHODDEF
#endif /* !defined(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 #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF
#define SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF
#endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */
/*[clinic end generated code: output=decd687b7631de4b input=a9049054013a1b77]*/ /*[clinic end generated code: output=39eb34a01fb9a919 input=a9049054013a1b77]*/

View File

@ -73,9 +73,6 @@ static const char usage_3[] = "\
tracemalloc module. By default, only the most recent frame is stored in a\n\ 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 of a trace. Use -X tracemalloc=NFRAME to start tracing with a\n\
traceback limit of NFRAME frames\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\ -X importtime: show how long each import takes. It shows module name,\n\
cumulative time (including nested imports) and self time (excluding\n\ cumulative time (including nested imports) and self time (excluding\n\
nested imports). Note that its output may be broken in multi-threaded\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(tracemalloc);
COPY_ATTR(import_time); COPY_ATTR(import_time);
COPY_ATTR(show_ref_count); COPY_ATTR(show_ref_count);
COPY_ATTR(show_alloc_count);
COPY_ATTR(dump_refs); COPY_ATTR(dump_refs);
COPY_ATTR(malloc_stats); COPY_ATTR(malloc_stats);
@ -903,7 +899,6 @@ config_as_dict(const PyConfig *config)
SET_ITEM_INT(tracemalloc); SET_ITEM_INT(tracemalloc);
SET_ITEM_INT(import_time); SET_ITEM_INT(import_time);
SET_ITEM_INT(show_ref_count); SET_ITEM_INT(show_ref_count);
SET_ITEM_INT(show_alloc_count);
SET_ITEM_INT(dump_refs); SET_ITEM_INT(dump_refs);
SET_ITEM_INT(malloc_stats); SET_ITEM_INT(malloc_stats);
SET_ITEM_WSTR(filesystem_encoding); SET_ITEM_WSTR(filesystem_encoding);
@ -1691,9 +1686,6 @@ config_read(PyConfig *config)
if (config_get_xoption(config, L"showrefcount")) { if (config_get_xoption(config, L"showrefcount")) {
config->show_ref_count = 1; config->show_ref_count = 1;
} }
if (config_get_xoption(config, L"showalloccount")) {
config->show_alloc_count = 1;
}
status = config_read_complex_options(config); status = config_read_complex_options(config);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {

View File

@ -1173,10 +1173,6 @@ Py_Initialize(void)
} }
#ifdef COUNT_ALLOCS
extern void _Py_dump_counts(FILE*);
#endif
/* Flush stdout and stderr */ /* Flush stdout and stderr */
static int static int
@ -1393,13 +1389,6 @@ Py_FinalizeEx(void)
* XXX I haven't seen a real-life report of either of these. * XXX I haven't seen a real-life report of either of these.
*/ */
_PyGC_CollectIfEnabled(); _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 */ /* Clear all loghooks */
/* We want minimal exposure of this function, so define the extern /* We want minimal exposure of this function, so define the extern
@ -1451,10 +1440,6 @@ Py_FinalizeEx(void)
/* unload faulthandler module */ /* unload faulthandler module */
_PyFaulthandler_Fini(); _PyFaulthandler_Fini();
/* Debugging stuff */
#ifdef COUNT_ALLOCS
_Py_dump_counts(stderr);
#endif
/* dump hash stats */ /* dump hash stats */
_PyHash_Fini(); _PyHash_Fini();

View File

@ -1685,20 +1685,6 @@ sys_getallocatedblocks_impl(PyObject *module)
return _Py_GetAllocatedBlocks(); 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] /*[clinic input]
sys._getframe sys._getframe
@ -1879,7 +1865,6 @@ static PyMethodDef sys_methods[] = {
SYS_GETDEFAULTENCODING_METHODDEF SYS_GETDEFAULTENCODING_METHODDEF
SYS_GETDLOPENFLAGS_METHODDEF SYS_GETDLOPENFLAGS_METHODDEF
SYS_GETALLOCATEDBLOCKS_METHODDEF SYS_GETALLOCATEDBLOCKS_METHODDEF
SYS_GETCOUNTS_METHODDEF
#ifdef DYNAMIC_EXECUTION_PROFILE #ifdef DYNAMIC_EXECUTION_PROFILE
{"getdxp", _Py_GetDXProfile, METH_VARARGS}, {"getdxp", _Py_GetDXProfile, METH_VARARGS},
#endif #endif