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