mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
gh-102567: Add -X importtime=2 for logging an importtime message for already-loaded modules (#118655)
Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
parent
e6f8e0a035
commit
c4bcc6a778
15 changed files with 166 additions and 44 deletions
|
@ -363,7 +363,7 @@ Configuration Options
|
||||||
- Read-only
|
- Read-only
|
||||||
* - ``"import_time"``
|
* - ``"import_time"``
|
||||||
- :c:member:`import_time <PyConfig.import_time>`
|
- :c:member:`import_time <PyConfig.import_time>`
|
||||||
- ``bool``
|
- ``int``
|
||||||
- Read-only
|
- Read-only
|
||||||
* - ``"inspect"``
|
* - ``"inspect"``
|
||||||
- :c:member:`inspect <PyConfig.inspect>`
|
- :c:member:`inspect <PyConfig.inspect>`
|
||||||
|
@ -1477,13 +1477,19 @@ PyConfig
|
||||||
|
|
||||||
.. c:member:: int import_time
|
.. c:member:: int import_time
|
||||||
|
|
||||||
If non-zero, profile import time.
|
If ``1``, profile import time.
|
||||||
|
If ``2``, include additional output that indicates
|
||||||
|
when an imported module has already been loaded.
|
||||||
|
|
||||||
Set the ``1`` by the :option:`-X importtime <-X>` option and the
|
Set by the :option:`-X importtime <-X>` option and the
|
||||||
:envvar:`PYTHONPROFILEIMPORTTIME` environment variable.
|
:envvar:`PYTHONPROFILEIMPORTTIME` environment variable.
|
||||||
|
|
||||||
Default: ``0``.
|
Default: ``0``.
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
|
||||||
|
Added support for ``import_time = 2``
|
||||||
|
|
||||||
.. c:member:: int inspect
|
.. c:member:: int inspect
|
||||||
|
|
||||||
Enter interactive mode after executing a script or a command.
|
Enter interactive mode after executing a script or a command.
|
||||||
|
|
|
@ -539,11 +539,21 @@ Miscellaneous options
|
||||||
* ``-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
|
||||||
application. Typical usage is ``python3 -X importtime -c 'import
|
application. Typical usage is ``python -X importtime -c 'import asyncio'``.
|
||||||
asyncio'``. See also :envvar:`PYTHONPROFILEIMPORTTIME`.
|
|
||||||
|
``-X importtime=2`` enables additional output that indicates when an
|
||||||
|
imported module has already been loaded. In such cases, the string
|
||||||
|
``cached`` will be printed in both time columns.
|
||||||
|
|
||||||
|
See also :envvar:`PYTHONPROFILEIMPORTTIME`.
|
||||||
|
|
||||||
.. versionadded:: 3.7
|
.. versionadded:: 3.7
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
|
||||||
|
Added ``-X importtime=2`` to also trace imports of loaded modules,
|
||||||
|
and reserved values other than ``1`` and ``2`` for future use.
|
||||||
|
|
||||||
* ``-X dev``: enable :ref:`Python Development Mode <devmode>`, introducing
|
* ``-X dev``: enable :ref:`Python Development Mode <devmode>`, introducing
|
||||||
additional runtime checks that are too expensive to be enabled by
|
additional runtime checks that are too expensive to be enabled by
|
||||||
default. See also :envvar:`PYTHONDEVMODE`.
|
default. See also :envvar:`PYTHONDEVMODE`.
|
||||||
|
@ -982,12 +992,17 @@ conflict.
|
||||||
|
|
||||||
.. envvar:: PYTHONPROFILEIMPORTTIME
|
.. envvar:: PYTHONPROFILEIMPORTTIME
|
||||||
|
|
||||||
If this environment variable is set to a non-empty string, Python will
|
If this environment variable is set to ``1``, Python will show
|
||||||
show how long each import takes.
|
how long each import takes. If set to ``2``, Python will include output for
|
||||||
|
imported modules that have already been loaded.
|
||||||
This is equivalent to setting the :option:`-X` ``importtime`` option.
|
This is equivalent to setting the :option:`-X` ``importtime`` option.
|
||||||
|
|
||||||
.. versionadded:: 3.7
|
.. versionadded:: 3.7
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
|
||||||
|
Added ``PYTHONPROFILEIMPORTTIME=2`` to also trace imports of loaded modules.
|
||||||
|
|
||||||
|
|
||||||
.. envvar:: PYTHONASYNCIODEBUG
|
.. envvar:: PYTHONASYNCIODEBUG
|
||||||
|
|
||||||
|
|
|
@ -789,6 +789,13 @@ Other language changes
|
||||||
of HMAC is not available.
|
of HMAC is not available.
|
||||||
(Contributed by Bénédikt Tran in :gh:`99108`.)
|
(Contributed by Bénédikt Tran in :gh:`99108`.)
|
||||||
|
|
||||||
|
* The import time flag can now track modules that are already loaded ('cached'),
|
||||||
|
via the new :option:`-X importtime=2 <-X>`.
|
||||||
|
When such a module is imported, the ``self`` and ``cumulative`` times
|
||||||
|
are replaced by the string ``cached``.
|
||||||
|
Values above ``2`` for ``-X importtime`` are now reserved for future use.
|
||||||
|
(Contributed by Noah Kim and Adam Turner in :gh:`118655`.)
|
||||||
|
|
||||||
* When subclassing from a pure C type, the C slots for the new type are no
|
* When subclassing from a pure C type, the C slots for the new type are no
|
||||||
longer replaced with a wrapped version on class creation if they are not
|
longer replaced with a wrapped version on class creation if they are not
|
||||||
explicitly overridden in the subclass.
|
explicitly overridden in the subclass.
|
||||||
|
|
|
@ -29,6 +29,7 @@ import signal
|
||||||
import struct
|
import struct
|
||||||
import termios
|
import termios
|
||||||
import time
|
import time
|
||||||
|
import types
|
||||||
import platform
|
import platform
|
||||||
from fcntl import ioctl
|
from fcntl import ioctl
|
||||||
|
|
||||||
|
@ -39,6 +40,12 @@ from .trace import trace
|
||||||
from .unix_eventqueue import EventQueue
|
from .unix_eventqueue import EventQueue
|
||||||
from .utils import wlen
|
from .utils import wlen
|
||||||
|
|
||||||
|
# declare posix optional to allow None assignment on other platforms
|
||||||
|
posix: types.ModuleType | None
|
||||||
|
try:
|
||||||
|
import posix
|
||||||
|
except ImportError:
|
||||||
|
posix = None
|
||||||
|
|
||||||
TYPE_CHECKING = False
|
TYPE_CHECKING = False
|
||||||
|
|
||||||
|
@ -556,11 +563,9 @@ class UnixConsole(Console):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def input_hook(self):
|
def input_hook(self):
|
||||||
try:
|
# avoid inline imports here so the repl doesn't get flooded
|
||||||
import posix
|
# with import logging from -X importtime=2
|
||||||
except ImportError:
|
if posix is not None and posix._is_inputhook_installed():
|
||||||
return None
|
|
||||||
if posix._is_inputhook_installed():
|
|
||||||
return posix._inputhook
|
return posix._inputhook
|
||||||
|
|
||||||
def __enable_bracketed_paste(self) -> None:
|
def __enable_bracketed_paste(self) -> None:
|
||||||
|
|
|
@ -24,6 +24,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import types
|
||||||
from ctypes.wintypes import (
|
from ctypes.wintypes import (
|
||||||
_COORD,
|
_COORD,
|
||||||
WORD,
|
WORD,
|
||||||
|
@ -58,6 +59,12 @@ except:
|
||||||
self.err = err
|
self.err = err
|
||||||
self.descr = descr
|
self.descr = descr
|
||||||
|
|
||||||
|
# declare nt optional to allow None assignment on other platforms
|
||||||
|
nt: types.ModuleType | None
|
||||||
|
try:
|
||||||
|
import nt
|
||||||
|
except ImportError:
|
||||||
|
nt = None
|
||||||
|
|
||||||
TYPE_CHECKING = False
|
TYPE_CHECKING = False
|
||||||
|
|
||||||
|
@ -121,9 +128,8 @@ class _error(Exception):
|
||||||
|
|
||||||
def _supports_vt():
|
def _supports_vt():
|
||||||
try:
|
try:
|
||||||
import nt
|
|
||||||
return nt._supports_virtual_terminal()
|
return nt._supports_virtual_terminal()
|
||||||
except (ImportError, AttributeError):
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class WindowsConsole(Console):
|
class WindowsConsole(Console):
|
||||||
|
@ -235,11 +241,9 @@ class WindowsConsole(Console):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def input_hook(self):
|
def input_hook(self):
|
||||||
try:
|
# avoid inline imports here so the repl doesn't get flooded
|
||||||
import nt
|
# with import logging from -X importtime=2
|
||||||
except ImportError:
|
if nt is not None and nt._is_inputhook_installed():
|
||||||
return None
|
|
||||||
if nt._is_inputhook_installed():
|
|
||||||
return nt._inputhook
|
return nt._inputhook
|
||||||
|
|
||||||
def __write_changed_line(
|
def __write_changed_line(
|
||||||
|
|
|
@ -57,7 +57,7 @@ class CAPITests(unittest.TestCase):
|
||||||
("home", str | None, None),
|
("home", str | None, None),
|
||||||
("thread_inherit_context", int, None),
|
("thread_inherit_context", int, None),
|
||||||
("context_aware_warnings", int, None),
|
("context_aware_warnings", int, None),
|
||||||
("import_time", bool, None),
|
("import_time", int, None),
|
||||||
("inspect", bool, None),
|
("inspect", bool, None),
|
||||||
("install_signal_handlers", bool, None),
|
("install_signal_handlers", bool, None),
|
||||||
("int_max_str_digits", int, None),
|
("int_max_str_digits", int, None),
|
||||||
|
|
|
@ -1158,6 +1158,24 @@ class CmdLineTest(unittest.TestCase):
|
||||||
res = assert_python_ok('-c', code, PYTHON_CPU_COUNT='default')
|
res = assert_python_ok('-c', code, PYTHON_CPU_COUNT='default')
|
||||||
self.assertEqual(self.res2int(res), (os.cpu_count(), os.process_cpu_count()))
|
self.assertEqual(self.res2int(res), (os.cpu_count(), os.process_cpu_count()))
|
||||||
|
|
||||||
|
def test_import_time(self):
|
||||||
|
# os is not imported at startup
|
||||||
|
code = 'import os; import os'
|
||||||
|
|
||||||
|
for case in 'importtime', 'importtime=1', 'importtime=true':
|
||||||
|
res = assert_python_ok('-X', case, '-c', code)
|
||||||
|
res_err = res.err.decode('utf-8')
|
||||||
|
self.assertRegex(res_err, r'import time: \s*\d+ \| \s*\d+ \| \s*os')
|
||||||
|
self.assertNotRegex(res_err, r'import time: cached\s* \| cached\s* \| os')
|
||||||
|
|
||||||
|
res = assert_python_ok('-X', 'importtime=2', '-c', code)
|
||||||
|
res_err = res.err.decode('utf-8')
|
||||||
|
self.assertRegex(res_err, r'import time: \s*\d+ \| \s*\d+ \| \s*os')
|
||||||
|
self.assertRegex(res_err, r'import time: cached\s* \| cached\s* \| os')
|
||||||
|
|
||||||
|
assert_python_failure('-X', 'importtime=-1', '-c', code)
|
||||||
|
assert_python_failure('-X', 'importtime=3', '-c', code)
|
||||||
|
|
||||||
def res2int(self, res):
|
def res2int(self, res):
|
||||||
out = res.out.strip().decode("utf-8")
|
out = res.out.strip().decode("utf-8")
|
||||||
return tuple(int(i) for i in out.split())
|
return tuple(int(i) for i in out.split())
|
||||||
|
|
|
@ -585,7 +585,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
'faulthandler': False,
|
'faulthandler': False,
|
||||||
'tracemalloc': 0,
|
'tracemalloc': 0,
|
||||||
'perf_profiling': 0,
|
'perf_profiling': 0,
|
||||||
'import_time': False,
|
'import_time': 0,
|
||||||
'thread_inherit_context': DEFAULT_THREAD_INHERIT_CONTEXT,
|
'thread_inherit_context': DEFAULT_THREAD_INHERIT_CONTEXT,
|
||||||
'context_aware_warnings': DEFAULT_CONTEXT_AWARE_WARNINGS,
|
'context_aware_warnings': DEFAULT_CONTEXT_AWARE_WARNINGS,
|
||||||
'code_debug_ranges': True,
|
'code_debug_ranges': True,
|
||||||
|
@ -998,7 +998,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
'hash_seed': 123,
|
'hash_seed': 123,
|
||||||
'tracemalloc': 2,
|
'tracemalloc': 2,
|
||||||
'perf_profiling': 0,
|
'perf_profiling': 0,
|
||||||
'import_time': True,
|
'import_time': 2,
|
||||||
'code_debug_ranges': False,
|
'code_debug_ranges': False,
|
||||||
'show_ref_count': True,
|
'show_ref_count': True,
|
||||||
'malloc_stats': True,
|
'malloc_stats': True,
|
||||||
|
@ -1064,7 +1064,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
'use_hash_seed': True,
|
'use_hash_seed': True,
|
||||||
'hash_seed': 42,
|
'hash_seed': 42,
|
||||||
'tracemalloc': 2,
|
'tracemalloc': 2,
|
||||||
'import_time': True,
|
'import_time': 1,
|
||||||
'code_debug_ranges': False,
|
'code_debug_ranges': False,
|
||||||
'malloc_stats': True,
|
'malloc_stats': True,
|
||||||
'inspect': True,
|
'inspect': True,
|
||||||
|
@ -1100,7 +1100,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
'use_hash_seed': True,
|
'use_hash_seed': True,
|
||||||
'hash_seed': 42,
|
'hash_seed': 42,
|
||||||
'tracemalloc': 2,
|
'tracemalloc': 2,
|
||||||
'import_time': True,
|
'import_time': 1,
|
||||||
'code_debug_ranges': False,
|
'code_debug_ranges': False,
|
||||||
'malloc_stats': True,
|
'malloc_stats': True,
|
||||||
'inspect': True,
|
'inspect': True,
|
||||||
|
|
|
@ -561,6 +561,7 @@ class TestSupport(unittest.TestCase):
|
||||||
['-Wignore', '-X', 'dev'],
|
['-Wignore', '-X', 'dev'],
|
||||||
['-X', 'faulthandler'],
|
['-X', 'faulthandler'],
|
||||||
['-X', 'importtime'],
|
['-X', 'importtime'],
|
||||||
|
['-X', 'importtime=2'],
|
||||||
['-X', 'showrefcount'],
|
['-X', 'showrefcount'],
|
||||||
['-X', 'tracemalloc'],
|
['-X', 'tracemalloc'],
|
||||||
['-X', 'tracemalloc=3'],
|
['-X', 'tracemalloc=3'],
|
||||||
|
|
|
@ -966,6 +966,7 @@ Beomsoo Bombs Kim
|
||||||
Derek D. Kim
|
Derek D. Kim
|
||||||
Gihwan Kim
|
Gihwan Kim
|
||||||
Jan Kim
|
Jan Kim
|
||||||
|
Noah Kim
|
||||||
Taek Joo Kim
|
Taek Joo Kim
|
||||||
Yeojin Kim
|
Yeojin Kim
|
||||||
Sam Kimbrel
|
Sam Kimbrel
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
:option:`-X importtime <-X>` now accepts value ``2``, which indicates that
|
||||||
|
an ``importtime`` entry should also be printed if an imported module has
|
||||||
|
already been loaded.
|
||||||
|
Patch by Noah Kim and Adam Turner.
|
|
@ -344,6 +344,10 @@ Set implementation-specific option. The following options are available:
|
||||||
application. Typical usage is
|
application. Typical usage is
|
||||||
\fBpython3 \-X importtime \-c 'import asyncio'\fR
|
\fBpython3 \-X importtime \-c 'import asyncio'\fR
|
||||||
|
|
||||||
|
\fB\-X importtime=2\fR enables additional output that indicates when an
|
||||||
|
imported module has already been loaded. In such cases, the string
|
||||||
|
\fBcached\fR will be printed in both time columns.
|
||||||
|
|
||||||
\fB\-X faulthandler\fR: enable faulthandler
|
\fB\-X faulthandler\fR: enable faulthandler
|
||||||
|
|
||||||
\fB\-X frozen_modules=\fR[\fBon\fR|\fBoff\fR]: whether or not frozen modules
|
\fB\-X frozen_modules=\fR[\fBon\fR|\fBoff\fR]: whether or not frozen modules
|
||||||
|
@ -648,9 +652,10 @@ See also the \fB\-X perf\fR option.
|
||||||
.IP PYTHONPLATLIBDIR
|
.IP PYTHONPLATLIBDIR
|
||||||
Override sys.platlibdir.
|
Override sys.platlibdir.
|
||||||
.IP PYTHONPROFILEIMPORTTIME
|
.IP PYTHONPROFILEIMPORTTIME
|
||||||
If this environment variable is set to a non-empty string, Python will
|
If this environment variable is set to \fB1\fR, Python will show
|
||||||
show how long each import takes. This is exactly equivalent to setting
|
how long each import takes. If set to \fB2\fR, Python will include output for
|
||||||
\fB\-X importtime\fP on the command line.
|
imported modules that have already been loaded.
|
||||||
|
This is exactly equivalent to setting \fB\-X importtime\fP on the command line.
|
||||||
.IP PYTHONPYCACHEPREFIX
|
.IP PYTHONPYCACHEPREFIX
|
||||||
If this is set, Python will write \fB.pyc\fR files in a mirror directory tree
|
If this is set, Python will write \fB.pyc\fR files in a mirror directory tree
|
||||||
at this path, instead of in \fB__pycache__\fR directories within the source
|
at this path, instead of in \fB__pycache__\fR directories within the source
|
||||||
|
|
|
@ -651,8 +651,8 @@ static int test_init_from_config(void)
|
||||||
putenv("PYTHONTRACEMALLOC=0");
|
putenv("PYTHONTRACEMALLOC=0");
|
||||||
config.tracemalloc = 2;
|
config.tracemalloc = 2;
|
||||||
|
|
||||||
putenv("PYTHONPROFILEIMPORTTIME=0");
|
putenv("PYTHONPROFILEIMPORTTIME=1");
|
||||||
config.import_time = 1;
|
config.import_time = 2;
|
||||||
|
|
||||||
putenv("PYTHONNODEBUGRANGES=0");
|
putenv("PYTHONNODEBUGRANGES=0");
|
||||||
config.code_debug_ranges = 0;
|
config.code_debug_ranges = 0;
|
||||||
|
|
|
@ -103,6 +103,15 @@ static struct _inittab *inittab_copy = NULL;
|
||||||
#define FIND_AND_LOAD(interp) \
|
#define FIND_AND_LOAD(interp) \
|
||||||
(interp)->imports.find_and_load
|
(interp)->imports.find_and_load
|
||||||
|
|
||||||
|
#define _IMPORT_TIME_HEADER(interp) \
|
||||||
|
do { \
|
||||||
|
if (FIND_AND_LOAD((interp)).header) { \
|
||||||
|
fputs("import time: self [us] | cumulative | imported package\n", \
|
||||||
|
stderr); \
|
||||||
|
FIND_AND_LOAD((interp)).header = 0; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
/*******************/
|
/*******************/
|
||||||
/* the import lock */
|
/* the import lock */
|
||||||
|
@ -246,9 +255,13 @@ import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *n
|
||||||
rc = _PyModuleSpec_IsInitializing(spec);
|
rc = _PyModuleSpec_IsInitializing(spec);
|
||||||
Py_DECREF(spec);
|
Py_DECREF(spec);
|
||||||
}
|
}
|
||||||
if (rc <= 0) {
|
if (rc == 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else if (rc < 0) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait until module is done importing. */
|
/* Wait until module is done importing. */
|
||||||
PyObject *value = PyObject_CallMethodOneArg(
|
PyObject *value = PyObject_CallMethodOneArg(
|
||||||
IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name);
|
IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name);
|
||||||
|
@ -256,6 +269,19 @@ import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *n
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* When -X importtime=2, print an import time entry even if an
|
||||||
|
imported module has already been loaded.
|
||||||
|
*/
|
||||||
|
if (_PyInterpreterState_GetConfig(interp)->import_time == 2) {
|
||||||
|
_IMPORT_TIME_HEADER(interp);
|
||||||
|
#define import_level FIND_AND_LOAD(interp).import_level
|
||||||
|
fprintf(stderr, "import time: cached | cached | %*s\n",
|
||||||
|
import_level*2, PyUnicode_AsUTF8(name));
|
||||||
|
#undef import_level
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3686,13 +3712,7 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name)
|
||||||
* _PyDict_GetItemIdWithError().
|
* _PyDict_GetItemIdWithError().
|
||||||
*/
|
*/
|
||||||
if (import_time) {
|
if (import_time) {
|
||||||
#define header FIND_AND_LOAD(interp).header
|
_IMPORT_TIME_HEADER(interp);
|
||||||
if (header) {
|
|
||||||
fputs("import time: self [us] | cumulative | imported package\n",
|
|
||||||
stderr);
|
|
||||||
header = 0;
|
|
||||||
}
|
|
||||||
#undef header
|
|
||||||
|
|
||||||
import_level++;
|
import_level++;
|
||||||
// ignore error: don't block import if reading the clock fails
|
// ignore error: don't block import if reading the clock fails
|
||||||
|
|
|
@ -153,7 +153,7 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
|
||||||
SPEC(home, WSTR_OPT, READ_ONLY, NO_SYS),
|
SPEC(home, WSTR_OPT, READ_ONLY, NO_SYS),
|
||||||
SPEC(thread_inherit_context, INT, READ_ONLY, NO_SYS),
|
SPEC(thread_inherit_context, INT, READ_ONLY, NO_SYS),
|
||||||
SPEC(context_aware_warnings, INT, READ_ONLY, NO_SYS),
|
SPEC(context_aware_warnings, INT, READ_ONLY, NO_SYS),
|
||||||
SPEC(import_time, BOOL, READ_ONLY, NO_SYS),
|
SPEC(import_time, UINT, READ_ONLY, NO_SYS),
|
||||||
SPEC(install_signal_handlers, BOOL, READ_ONLY, NO_SYS),
|
SPEC(install_signal_handlers, BOOL, READ_ONLY, NO_SYS),
|
||||||
SPEC(isolated, BOOL, READ_ONLY, NO_SYS), // sys.flags.isolated
|
SPEC(isolated, BOOL, READ_ONLY, NO_SYS), // sys.flags.isolated
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
|
@ -312,7 +312,8 @@ The following implementation-specific options are available:\n\
|
||||||
"-X gil=[0|1]: enable (1) or disable (0) the GIL; also PYTHON_GIL\n"
|
"-X gil=[0|1]: enable (1) or disable (0) the GIL; also PYTHON_GIL\n"
|
||||||
#endif
|
#endif
|
||||||
"\
|
"\
|
||||||
-X importtime: show how long each import takes; also PYTHONPROFILEIMPORTTIME\n\
|
-X importtime[=2]: show how long each import takes; use -X importtime=2 to\
|
||||||
|
log imports of already-loaded modules; also PYTHONPROFILEIMPORTTIME\n\
|
||||||
-X int_max_str_digits=N: limit the size of int<->str conversions;\n\
|
-X int_max_str_digits=N: limit the size of int<->str conversions;\n\
|
||||||
0 disables the limit; also PYTHONINTMAXSTRDIGITS\n\
|
0 disables the limit; also PYTHONINTMAXSTRDIGITS\n\
|
||||||
-X no_debug_ranges: don't include extra location information in code objects;\n\
|
-X no_debug_ranges: don't include extra location information in code objects;\n\
|
||||||
|
@ -1004,6 +1005,7 @@ _PyConfig_InitCompatConfig(PyConfig *config)
|
||||||
memset(config, 0, sizeof(*config));
|
memset(config, 0, sizeof(*config));
|
||||||
|
|
||||||
config->_config_init = (int)_PyConfig_INIT_COMPAT;
|
config->_config_init = (int)_PyConfig_INIT_COMPAT;
|
||||||
|
config->import_time = -1;
|
||||||
config->isolated = -1;
|
config->isolated = -1;
|
||||||
config->use_environment = -1;
|
config->use_environment = -1;
|
||||||
config->dev_mode = -1;
|
config->dev_mode = -1;
|
||||||
|
@ -2246,6 +2248,38 @@ config_init_run_presite(PyConfig *config)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static PyStatus
|
||||||
|
config_init_import_time(PyConfig *config)
|
||||||
|
{
|
||||||
|
int importtime = 0;
|
||||||
|
|
||||||
|
const char *env = config_get_env(config, "PYTHONPROFILEIMPORTTIME");
|
||||||
|
if (env) {
|
||||||
|
if (_Py_str_to_int(env, &importtime) != 0) {
|
||||||
|
importtime = 1;
|
||||||
|
}
|
||||||
|
if (importtime < 0 || importtime > 2) {
|
||||||
|
return _PyStatus_ERR(
|
||||||
|
"PYTHONPROFILEIMPORTTIME: numeric values other than 1 and 2 "
|
||||||
|
"are reserved for future use.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *x_value = config_get_xoption_value(config, L"importtime");
|
||||||
|
if (x_value) {
|
||||||
|
if (*x_value == 0 || config_wstr_to_int(x_value, &importtime) != 0) {
|
||||||
|
importtime = 1;
|
||||||
|
}
|
||||||
|
if (importtime < 0 || importtime > 2) {
|
||||||
|
return _PyStatus_ERR(
|
||||||
|
"-X importtime: values other than 1 and 2 "
|
||||||
|
"are reserved for future use.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config->import_time = importtime;
|
||||||
|
return _PyStatus_OK();
|
||||||
|
}
|
||||||
|
|
||||||
static PyStatus
|
static PyStatus
|
||||||
config_read_complex_options(PyConfig *config)
|
config_read_complex_options(PyConfig *config)
|
||||||
|
@ -2257,17 +2291,19 @@ config_read_complex_options(PyConfig *config)
|
||||||
config->faulthandler = 1;
|
config->faulthandler = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (config_get_env(config, "PYTHONPROFILEIMPORTTIME")
|
|
||||||
|| config_get_xoption(config, L"importtime")) {
|
|
||||||
config->import_time = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_get_env(config, "PYTHONNODEBUGRANGES")
|
if (config_get_env(config, "PYTHONNODEBUGRANGES")
|
||||||
|| config_get_xoption(config, L"no_debug_ranges")) {
|
|| config_get_xoption(config, L"no_debug_ranges")) {
|
||||||
config->code_debug_ranges = 0;
|
config->code_debug_ranges = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyStatus status;
|
PyStatus status;
|
||||||
|
if (config->import_time < 0) {
|
||||||
|
status = config_init_import_time(config);
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (config->tracemalloc < 0) {
|
if (config->tracemalloc < 0) {
|
||||||
status = config_init_tracemalloc(config);
|
status = config_init_tracemalloc(config);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue