summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-11-29 16:20:38 (GMT)
committerGitHub <noreply@github.com>2017-11-29 16:20:38 (GMT)
commit5d39e0429029324cae90bba2f19fb689b007c7d6 (patch)
treed414a4bc635c750d07c93d94835d932d3524c062 /Lib
parentc15bb49d71f97d400b295d88e5b075e89cb8ba20 (diff)
downloadcpython-5d39e0429029324cae90bba2f19fb689b007c7d6.zip
cpython-5d39e0429029324cae90bba2f19fb689b007c7d6.tar.gz
cpython-5d39e0429029324cae90bba2f19fb689b007c7d6.tar.bz2
bpo-32030: Rework memory allocators (#4625)
* Fix _PyMem_SetupAllocators("debug"): always restore allocators to the defaults, rather than only caling _PyMem_SetupDebugHooks(). * Add _PyMem_SetDefaultAllocator() helper to set the "default" allocator. * Add _PyMem_GetAllocatorsName(): get the name of the allocators * main() now uses debug hooks on memory allocators if Py_DEBUG is defined, rather than calling directly malloc() * Document default memory allocators in C API documentation * _Py_InitializeCore() now fails with a fatal user error if PYTHONMALLOC value is an unknown memory allocator, instead of failing with a fatal internal error. * Add new tests on the PYTHONMALLOC environment variable * Add support.with_pymalloc() * Add the _testcapi.WITH_PYMALLOC constant and expose it as support.with_pymalloc(). * sysconfig.get_config_var('WITH_PYMALLOC') doesn't work on Windows, so replace it with support.with_pymalloc(). * pythoninfo: add _testcapi collector for pymem
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/pythoninfo.py50
-rw-r--r--Lib/test/support/__init__.py5
-rw-r--r--Lib/test/test_capi.py3
-rw-r--r--Lib/test/test_cmd_line.py52
-rw-r--r--Lib/test/test_sys.py9
5 files changed, 96 insertions, 23 deletions
diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
index 85e32a9..7ad076d 100644
--- a/Lib/test/pythoninfo.py
+++ b/Lib/test/pythoninfo.py
@@ -56,6 +56,14 @@ def copy_attributes(info_add, obj, name_fmt, attributes, *, formatter=None):
info_add(name, value)
+def copy_attr(info_add, name, mod, attr_name):
+ try:
+ value = getattr(mod, attr_name)
+ except AttributeError:
+ return
+ info_add(name, value)
+
+
def call_func(info_add, name, mod, func_name, *, formatter=None):
try:
func = getattr(mod, func_name)
@@ -168,11 +176,10 @@ def collect_os(info_add):
call_func(info_add, 'os.gid', os, 'getgid')
call_func(info_add, 'os.uname', os, 'uname')
- if hasattr(os, 'getgroups'):
- groups = os.getgroups()
- groups = map(str, groups)
- groups = ', '.join(groups)
- info_add("os.groups", groups)
+ def format_groups(groups):
+ return ', '.join(map(str, groups))
+
+ call_func(info_add, 'os.groups', os, 'getgroups', formatter=format_groups)
if hasattr(os, 'getlogin'):
try:
@@ -184,11 +191,7 @@ def collect_os(info_add):
else:
info_add("os.login", login)
- if hasattr(os, 'cpu_count'):
- cpu_count = os.cpu_count()
- if cpu_count:
- info_add('os.cpu_count', cpu_count)
-
+ call_func(info_add, 'os.cpu_count', os, 'cpu_count')
call_func(info_add, 'os.loadavg', os, 'getloadavg')
# Get environment variables: filter to list
@@ -219,7 +222,9 @@ def collect_os(info_add):
)
for name, value in os.environ.items():
uname = name.upper()
- if (uname in ENV_VARS or uname.startswith(("PYTHON", "LC_"))
+ if (uname in ENV_VARS
+ # Copy PYTHON* and LC_* variables
+ or uname.startswith(("PYTHON", "LC_"))
# Visual Studio: VS140COMNTOOLS
or (uname.startswith("VS") and uname.endswith("COMNTOOLS"))):
info_add('os.environ[%s]' % name, value)
@@ -313,12 +318,10 @@ def collect_time(info_add):
)
copy_attributes(info_add, time, 'time.%s', attributes)
- if not hasattr(time, 'get_clock_info'):
- return
-
- for clock in ('time', 'perf_counter'):
- tinfo = time.get_clock_info(clock)
- info_add('time.%s' % clock, tinfo)
+ if hasattr(time, 'get_clock_info'):
+ for clock in ('time', 'perf_counter'):
+ tinfo = time.get_clock_info(clock)
+ info_add('time.%s' % clock, tinfo)
def collect_sysconfig(info_add):
@@ -331,7 +334,6 @@ def collect_sysconfig(info_add):
'CCSHARED',
'CFLAGS',
'CFLAGSFORSHARED',
- 'PY_LDFLAGS',
'CONFIG_ARGS',
'HOST_GNU_TYPE',
'MACHDEP',
@@ -339,6 +341,7 @@ def collect_sysconfig(info_add):
'OPT',
'PY_CFLAGS',
'PY_CFLAGS_NODIST',
+ 'PY_LDFLAGS',
'Py_DEBUG',
'Py_ENABLE_SHARED',
'SHELL',
@@ -422,6 +425,16 @@ def collect_decimal(info_add):
copy_attributes(info_add, _decimal, '_decimal.%s', attributes)
+def collect_testcapi(info_add):
+ try:
+ import _testcapi
+ except ImportError:
+ return
+
+ call_func(info_add, 'pymem.allocator', _testcapi, 'pymem_getallocatorsname')
+ copy_attr(info_add, 'pymem.with_pymalloc', _testcapi, 'WITH_PYMALLOC')
+
+
def collect_info(info):
error = False
info_add = info.add
@@ -444,6 +457,7 @@ def collect_info(info):
collect_zlib,
collect_expat,
collect_decimal,
+ collect_testcapi,
):
try:
collect_func(info_add)
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 42c41ff..f0e1507 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2848,3 +2848,8 @@ class SaveSignals:
def restore(self):
for signum, handler in self.handlers.items():
self.signal.signal(signum, handler)
+
+
+def with_pymalloc():
+ import _testcapi
+ return _testcapi.WITH_PYMALLOC
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 7a10cda..2a6de3c 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -654,8 +654,7 @@ class PyMemMallocDebugTests(PyMemDebugTests):
PYTHONMALLOC = 'malloc_debug'
-@unittest.skipUnless(sysconfig.get_config_var('WITH_PYMALLOC') == 1,
- 'need pymalloc')
+@unittest.skipUnless(support.with_pymalloc(), 'need pymalloc')
class PyMemPymallocDebugTests(PyMemDebugTests):
PYTHONMALLOC = 'pymalloc_debug'
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index 7f95fcc..96405e7 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -5,6 +5,7 @@
import os
import subprocess
import sys
+import sysconfig
import tempfile
import unittest
from test import support
@@ -559,10 +560,14 @@ class CmdLineTest(unittest.TestCase):
except ImportError:
pass
else:
- code = "import _testcapi; _testcapi.pymem_api_misuse()"
+ code = "import _testcapi; print(_testcapi.pymem_getallocatorsname())"
with support.SuppressCrashReport():
out = self.run_xdev("-c", code, check_exitcode=False)
- self.assertIn("Debug memory block at address p=", out)
+ if support.with_pymalloc():
+ alloc_name = "pymalloc_debug"
+ else:
+ alloc_name = "malloc_debug"
+ self.assertEqual(out, alloc_name)
try:
import faulthandler
@@ -573,6 +578,49 @@ class CmdLineTest(unittest.TestCase):
out = self.run_xdev("-c", code)
self.assertEqual(out, "True")
+ def check_pythonmalloc(self, env_var, name):
+ code = 'import _testcapi; print(_testcapi.pymem_getallocatorsname())'
+ env = dict(os.environ)
+ if env_var is not None:
+ env['PYTHONMALLOC'] = env_var
+ else:
+ env.pop('PYTHONMALLOC', None)
+ args = (sys.executable, '-c', code)
+ proc = subprocess.run(args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True,
+ env=env)
+ self.assertEqual(proc.stdout.rstrip(), name)
+ self.assertEqual(proc.returncode, 0)
+
+ def test_pythonmalloc(self):
+ # Test the PYTHONMALLOC environment variable
+ pydebug = hasattr(sys, "gettotalrefcount")
+ pymalloc = support.with_pymalloc()
+ if pymalloc:
+ default_name = 'pymalloc_debug' if pydebug else 'pymalloc'
+ default_name_debug = 'pymalloc_debug'
+ else:
+ default_name = 'malloc_debug' if pydebug else 'malloc'
+ default_name_debug = 'malloc_debug'
+
+ tests = [
+ (None, default_name),
+ ('debug', default_name_debug),
+ ('malloc', 'malloc'),
+ ('malloc_debug', 'malloc_debug'),
+ ]
+ if pymalloc:
+ tests.extend((
+ ('pymalloc', 'pymalloc'),
+ ('pymalloc_debug', 'pymalloc_debug'),
+ ))
+
+ for env_var, name in tests:
+ with self.subTest(env_var=env_var, name=name):
+ self.check_pythonmalloc(env_var, name)
+
class IgnoreEnvironmentTest(unittest.TestCase):
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 20965b9..4b8fcb9 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -753,8 +753,15 @@ class SysModuleTest(unittest.TestCase):
@unittest.skipUnless(hasattr(sys, "getallocatedblocks"),
"sys.getallocatedblocks unavailable on this build")
def test_getallocatedblocks(self):
+ try:
+ import _testcapi
+ except ImportError:
+ with_pymalloc = support.with_pymalloc()
+ else:
+ alloc_name = _testcapi.pymem_getallocatorsname()
+ with_pymalloc = (alloc_name in ('pymalloc', 'pymalloc_debug'))
+
# Some sanity checks
- with_pymalloc = sysconfig.get_config_var('WITH_PYMALLOC')
a = sys.getallocatedblocks()
self.assertIs(type(a), int)
if with_pymalloc: