Skip to content

Commit

Permalink
bpo-39489: Remove COUNT_ALLOCS special build (GH-18259)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vstinner committed Feb 3, 2020
1 parent 869c0c9 commit c6e5c11
Show file tree
Hide file tree
Showing 34 changed files with 24 additions and 469 deletions.
12 changes: 4 additions & 8 deletions Doc/c-api/init_config.rst
Expand Up @@ -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?
Expand Down Expand Up @@ -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
----------------------------
Expand Down
34 changes: 0 additions & 34 deletions Doc/c-api/typeobj.rst
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions Doc/using/cmdline.rst
Expand Up @@ -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
Expand Down Expand Up @@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.9.rst
Expand Up @@ -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
==========
Expand Down Expand Up @@ -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
=====================
Expand Down
1 change: 0 additions & 1 deletion Include/cpython/initconfig.h
Expand Up @@ -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 */

Expand Down
11 changes: 0 additions & 11 deletions Include/cpython/object.h
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
}
Expand Down
20 changes: 2 additions & 18 deletions Include/object.h
Expand Up @@ -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);
Expand All @@ -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 */

Expand Down
2 changes: 1 addition & 1 deletion Lib/subprocess.py
Expand Up @@ -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:
Expand Down
3 changes: 0 additions & 3 deletions Lib/test/support/__init__.py
Expand Up @@ -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."""
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_embed.py
Expand Up @@ -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,

Expand Down Expand Up @@ -729,7 +728,6 @@ def test_init_from_config(self):
'tracemalloc': 2,
'import_time': 1,
'show_ref_count': 1,
'show_alloc_count': 1,
'malloc_stats': 1,

'stdio_encoding': 'iso8859-1',
Expand Down
6 changes: 1 addition & 5 deletions Lib/test/test_gc.py
Expand Up @@ -2,7 +2,7 @@
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

Expand Down Expand Up @@ -131,7 +131,6 @@ class A:
del a
self.assertNotEqual(gc.collect(), 0)

@requires_type_collecting
def test_newinstance(self):
class A(object):
pass
Expand Down Expand Up @@ -709,7 +708,6 @@ def run_command(code):
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.
Expand All @@ -723,7 +721,6 @@ def __del__(self):
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:
Expand All @@ -743,7 +740,6 @@ def __del__(self):
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:
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_io.py
Expand Up @@ -3492,7 +3492,6 @@ def __del__(self):
""".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:
Expand All @@ -3502,7 +3501,6 @@ def test_create_at_shutdown_without_encoding(self):
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')
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test_logging.py
Expand Up @@ -4252,7 +4252,6 @@ def __init__(self, name='MyLogger', level=logging.NOTSET):
h.close()
logging.setLoggerClass(logging.Logger)

@support.requires_type_collecting
def test_logging_at_shutdown(self):
# Issue #20037
code = """if 1:
Expand Down
4 changes: 1 addition & 3 deletions 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
Expand Down Expand Up @@ -101,7 +101,6 @@ def f():
gc_collect()
self.assertEqual(f().__dict__["bar"], 4)

@requires_type_collecting
def test_clear_dict_in_ref_cycle(self):
destroyed = []
m = ModuleType("foo")
Expand Down Expand Up @@ -266,7 +265,6 @@ def test_module_repr_source(self):
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")
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test_support.py
Expand Up @@ -493,7 +493,6 @@ def test_args_from_interpreter_flags(self):
['-Wignore', '-X', 'dev'],
['-X', 'faulthandler'],
['-X', 'importtime'],
['-X', 'showalloccount'],
['-X', 'showrefcount'],
['-X', 'tracemalloc'],
['-X', 'tracemalloc=3'],
Expand Down
4 changes: 0 additions & 4 deletions Lib/test/test_sys.py
Expand Up @@ -819,7 +819,6 @@ def test_getallocatedblocks(self):
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
Expand All @@ -841,7 +840,6 @@ def __del__(self):
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:
Expand Down Expand Up @@ -1295,8 +1293,6 @@ def delx(self): del self.__x
# type
# static type: PyTypeObject
fmt = 'P2nPI13Pl4Pn9Pn11PIPP'
if hasattr(sys, 'getcounts'):
fmt += '3n2P'
s = vsize(fmt)
check(int, s)
# class
Expand Down
5 changes: 1 addition & 4 deletions Lib/test/test_threading.py
Expand Up @@ -3,8 +3,7 @@
"""

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
Expand Down Expand Up @@ -552,7 +551,6 @@ def f():
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
Expand Down Expand Up @@ -1113,7 +1111,6 @@ def run():
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
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test_traceback.py
Expand Up @@ -174,7 +174,6 @@ def do_test(firstlines, message, charset, lineno):
# 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
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test_warnings/__init__.py
Expand Up @@ -1227,7 +1227,6 @@ def test_issue_8766(self):


class FinalizationTest(unittest.TestCase):
@support.requires_type_collecting
def test_finalization(self):
# Issue #19421: warnings.warn() should not crash
# during Python finalization
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test_weakref.py
Expand Up @@ -649,7 +649,6 @@ class D:
del c1, c2, C, D
gc.collect()

@support.requires_type_collecting
def test_callback_in_cycle_resurrection(self):
import gc

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

0 comments on commit c6e5c11

Please sign in to comment.