mirror of https://github.com/python/cpython
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:
parent
869c0c99b9
commit
c6e5c1123b
|
@ -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
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -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
|
||||||
=====================
|
=====================
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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."""
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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'],
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Remove ``COUNT_ALLOCS`` special build.
|
|
@ -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
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
126
Objects/object.c
126
Objects/object.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 **************************/
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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]*/
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue