Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit58d07be

Browse files
committed
Add -X importtime=2 for logging an importtime message for already-loaded modules
1 parentc141340 commit58d07be

File tree

12 files changed

+163
-31
lines changed

12 files changed

+163
-31
lines changed

‎Doc/c-api/init_config.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,9 +1477,10 @@ PyConfig
14771477
14781478
.. c:member:: int import_time
14791479
1480-
If non-zero, profile import time.
1480+
If non-zero, profile import time. If ``2``, include additional output that
1481+
indicates when an imported module has already been loaded.
14811482
1482-
Setthe ``1``by the :option:`-X importtime <-X>` option and the
1483+
Set by the :option:`-X importtime <-X>` option and the
14831484
:envvar:`PYTHONPROFILEIMPORTTIME` environment variable.
14841485
14851486
Default: ``0``.

‎Doc/using/cmdline.rst

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,17 @@ Miscellaneous options
542542
application. Typical usage is ``python3 -X importtime -c 'import
543543
asyncio'``. See also:envvar:`PYTHONPROFILEIMPORTTIME`.
544544

545+
``-X importtime=2`` enables additional output that indicates when an
546+
imported module has already been loaded. In such cases, the string
547+
``cached`` will be printed in the self time and cumulative time columns.
548+
545549
..versionadded::3.7
546550

551+
..versionchanged::next
552+
553+
Added ``-X importtime=2`` to also trace imports of loaded modules,
554+
and reserved values other than ``1`` and ``2`` for future use.
555+
547556
* ``-X dev``: enable:ref:`Python Development Mode<devmode>`, introducing
548557
additional runtime checks that are too expensive to be enabled by
549558
default. See also:envvar:`PYTHONDEVMODE`.
@@ -984,12 +993,17 @@ conflict.
984993

985994
..envvar::PYTHONPROFILEIMPORTTIME
986995

987-
If this environment variable is set to a non-empty string, Python will
988-
show how long each import takes.
996+
If this environment variable is set to ``1``, Python will show
997+
how long each import takes. If set to ``2``, Python will include output for
998+
imported modules that have already been loaded.
989999
This is equivalent to setting the:option:`-X` ``importtime`` option.
9901000

9911001
..versionadded::3.7
9921002

1003+
..versionchanged::next
1004+
1005+
Added ``PYTHONPROFILEIMPORTTIME=2`` to also trace imports of loaded modules.
1006+
9931007

9941008
..envvar::PYTHONASYNCIODEBUG
9951009

‎Doc/whatsnew/3.14.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,13 @@ Other language changes
626626
of HMAC is not available.
627627
(Contributed by Bénédikt Tran in:gh:`99108`.)
628628

629+
*:option:`-X importtime <-X>` now accepts value ``2``, which indicates that
630+
an ``importtime`` entry should also be printed if an imported module has
631+
already been loaded. The ``self`` and ``cumulative`` times for such entries
632+
are replaced by the string ``cached``.
633+
Values above ``2`` are now reserved for future use.
634+
(Contributed by Noah Kim in:gh:`118655`.)
635+
629636
* When subclassing from a pure C type, the C slots for the new type are no
630637
longer replaced with a wrapped version on class creation if they are not
631638
explicitly overridden in the subclass.

‎Lib/_pyrepl/unix_console.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
importstruct
3030
importtermios
3131
importtime
32+
importtypes
3233
importplatform
3334
fromfcntlimportioctl
3435

@@ -39,6 +40,13 @@
3940
from .unix_eventqueueimportEventQueue
4041
from .utilsimportwlen
4142

43+
# declare posix optional to allow None assignment on other platforms
44+
posix:types.ModuleType|None
45+
46+
try:
47+
importposix
48+
exceptImportError:
49+
posix=None
4250

4351
TYPE_CHECKING=False
4452

@@ -566,11 +574,9 @@ def clear(self):
566574

567575
@property
568576
definput_hook(self):
569-
try:
570-
importposix
571-
exceptImportError:
572-
returnNone
573-
ifposix._is_inputhook_installed():
577+
# avoid inline imports here so the repl doesn't get flooded with import
578+
# logging from -Ximporttime=2
579+
ifposixisnotNoneandposix._is_inputhook_installed():
574580
returnposix._inputhook
575581

576582
def__enable_bracketed_paste(self)->None:

‎Lib/_pyrepl/windows_console.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
importsys
2525

2626
importctypes
27+
importtypes
2728
fromctypes.wintypesimport (
2829
_COORD,
2930
WORD,
@@ -58,6 +59,12 @@ def __init__(self, err: int | None, descr: str | None = None) -> None:
5859
self.err=err
5960
self.descr=descr
6061

62+
nt:types.ModuleType|None
63+
64+
try:
65+
importnt
66+
exceptImportError:
67+
nt=None
6168

6269
TYPE_CHECKING=False
6370

@@ -121,9 +128,8 @@ class _error(Exception):
121128

122129
def_supports_vt():
123130
try:
124-
importnt
125-
returnnt._supports_virtual_terminal()
126-
except (ImportError,AttributeError):
131+
nt._supports_virtual_terminal()
132+
exceptAttributeError:
127133
returnFalse
128134

129135
classWindowsConsole(Console):
@@ -235,11 +241,9 @@ def refresh(self, screen: list[str], c_xy: tuple[int, int]) -> None:
235241

236242
@property
237243
definput_hook(self):
238-
try:
239-
importnt
240-
exceptImportError:
241-
returnNone
242-
ifnt._is_inputhook_installed():
244+
# avoid inline imports here so the repl doesn't get flooded with import
245+
# logging from -Ximporttime=2
246+
ifntisnotNoneandnt._is_inputhook_installed():
243247
returnnt._inputhook
244248

245249
def__write_changed_line(

‎Lib/test/test_capi/test_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def test_config_get(self):
5757
("home",str|None,None),
5858
("thread_inherit_context",int,None),
5959
("context_aware_warnings",int,None),
60-
("import_time",bool,None),
60+
("import_time",int,None),
6161
("inspect",bool,None),
6262
("install_signal_handlers",bool,None),
6363
("int_max_str_digits",int,None),

‎Lib/test/test_cmd_line.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,28 @@ def test_cpu_count_default(self):
11581158
res=assert_python_ok('-c',code,PYTHON_CPU_COUNT='default')
11591159
self.assertEqual(self.res2int(res), (os.cpu_count(),os.process_cpu_count()))
11601160

1161+
deftest_import_time(self):
1162+
code="import os"
1163+
res=assert_python_ok('-X','importtime','-c',code)
1164+
res_err=res.err.decode("utf-8")
1165+
self.assertRegex(res_err,r"import time: \s*\d+ \| \s*\d+ \| \s*os")
1166+
self.assertNotRegex(res_err,r"import time: cached\s* \| cached\s* \| os")
1167+
1168+
code="import os"
1169+
res=assert_python_ok('-X','importtime=true','-c',code)
1170+
res_err=res.err.decode("utf-8")
1171+
self.assertRegex(res_err,r"import time: \s*\d+ \| \s*\d+ \| \s*os")
1172+
self.assertNotRegex(res_err,r"import time: cached\s* \| cached\s* \| os")
1173+
1174+
code="import os; import os"
1175+
res=assert_python_ok('-X','importtime=2','-c',code)
1176+
res_err=res.err.decode("utf-8")
1177+
self.assertRegex(res_err,r"import time: \s*\d+ \| \s*\d+ \| \s*os")
1178+
self.assertRegex(res_err,r"import time: cached\s* \| cached\s* \| os")
1179+
1180+
assert_python_failure('-X','importtime=-1','-c',code)
1181+
assert_python_failure('-X','importtime=3','-c',code)
1182+
11611183
defres2int(self,res):
11621184
out=res.out.strip().decode("utf-8")
11631185
returntuple(int(i)foriinout.split())

‎Lib/test/test_embed.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
585585
'faulthandler':False,
586586
'tracemalloc':0,
587587
'perf_profiling':0,
588-
'import_time':False,
588+
'import_time':0,
589589
'thread_inherit_context':DEFAULT_THREAD_INHERIT_CONTEXT,
590590
'context_aware_warnings':DEFAULT_CONTEXT_AWARE_WARNINGS,
591591
'code_debug_ranges':True,
@@ -998,7 +998,7 @@ def test_init_from_config(self):
998998
'hash_seed':123,
999999
'tracemalloc':2,
10001000
'perf_profiling':0,
1001-
'import_time':True,
1001+
'import_time':0,
10021002
'code_debug_ranges':False,
10031003
'show_ref_count':True,
10041004
'malloc_stats':True,
@@ -1064,7 +1064,7 @@ def test_init_compat_env(self):
10641064
'use_hash_seed':True,
10651065
'hash_seed':42,
10661066
'tracemalloc':2,
1067-
'import_time':True,
1067+
'import_time':0,
10681068
'code_debug_ranges':False,
10691069
'malloc_stats':True,
10701070
'inspect':True,
@@ -1100,7 +1100,7 @@ def test_init_python_env(self):
11001100
'use_hash_seed':True,
11011101
'hash_seed':42,
11021102
'tracemalloc':2,
1103-
'import_time':True,
1103+
'import_time':0,
11041104
'code_debug_ranges':False,
11051105
'malloc_stats':True,
11061106
'inspect':True,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:option:`-X importtime <-X>` now accepts value ``2``, which indicates that
2+
an ``importtime`` entry should also be printed if an imported module has
3+
already been loaded.

‎Programs/_testembed.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ static int test_init_from_config(void)
652652
config.tracemalloc=2;
653653

654654
putenv("PYTHONPROFILEIMPORTTIME=0");
655-
config.import_time=1;
655+
config.import_time=0;
656656

657657
putenv("PYTHONNODEBUGRANGES=0");
658658
config.code_debug_ranges=0;

‎Python/import.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,32 @@ import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *n
246246
rc=_PyModuleSpec_IsInitializing(spec);
247247
Py_DECREF(spec);
248248
}
249-
if (rc <=0) {
249+
if (rc==0) {
250+
gotodone;
251+
}
252+
elseif (rc<0) {
250253
returnrc;
251254
}
255+
252256
/* Wait until module is done importing. */
253257
PyObject*value=PyObject_CallMethodOneArg(
254258
IMPORTLIB(interp),&_Py_ID(_lock_unlock_module),name);
255259
if (value==NULL) {
256260
return-1;
257261
}
258262
Py_DECREF(value);
263+
264+
done:
265+
/* When -Ximporttime=2, print an import time entry even if an
266+
* imported module has already been loaded.
267+
*/
268+
if (_PyInterpreterState_GetConfig(interp)->import_time >=2) {
269+
#defineimport_level FIND_AND_LOAD(interp).import_level
270+
fprintf(stderr,"import time: cached | cached | %*s\n",
271+
import_level*2,PyUnicode_AsUTF8(name));
272+
#undef import_level
273+
}
274+
259275
return0;
260276
}
261277

‎Python/initconfig.c

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
153153
SPEC(home,WSTR_OPT,READ_ONLY,NO_SYS),
154154
SPEC(thread_inherit_context,INT,READ_ONLY,NO_SYS),
155155
SPEC(context_aware_warnings,INT,READ_ONLY,NO_SYS),
156-
SPEC(import_time,BOOL,READ_ONLY,NO_SYS),
156+
SPEC(import_time,UINT,READ_ONLY,NO_SYS),
157157
SPEC(install_signal_handlers,BOOL,READ_ONLY,NO_SYS),
158158
SPEC(isolated,BOOL,READ_ONLY,NO_SYS),// sys.flags.isolated
159159
#ifdefMS_WINDOWS
@@ -312,7 +312,8 @@ The following implementation-specific options are available:\n\
312312
"-X gil=[0|1]: enable (1) or disable (0) the GIL; also PYTHON_GIL\n"
313313
#endif
314314
"\
315-
-Ximporttime:showhowlongeachimporttakes;alsoPYTHONPROFILEIMPORTTIME\n\
315+
-Ximporttime[=2]:showhow longeachimporttakes;-Ximporttime=2alsoprints\
316+
rowsforimportsofalready-loadedmodules;alsoPYTHONPROFILEIMPORTTIME\n\
316317
-Xint_max_str_digits=N:limitthesizeofint<->strconversions;\n\
317318
0disablesthelimit;alsoPYTHONINTMAXSTRDIGITS\n\
318319
-Xno_debug_ranges:don't include extra location information in code objects;\n\
@@ -2246,6 +2247,63 @@ config_init_run_presite(PyConfig *config)
22462247
}
22472248
#endif
22482249

2250+
/* Set `config->import_time` based on `value` from `-Ximporttime(=.*)?`. */
2251+
staticPyStatus
2252+
config_set_import_time(PyConfig*config,constwchar_t*value)
2253+
{
2254+
intnumeric_value;
2255+
2256+
// If no value is specified or the value is not an integer, use 1.
2257+
if (*value==0||config_wstr_to_int(value,&numeric_value)!=0) {
2258+
config->import_time=1;
2259+
}
2260+
2261+
/* -Ximporttime=1 incurs the default behavior. -Ximporttime=2 also
2262+
* prints import cache hits. All other numeric values are reserved.
2263+
*/
2264+
elseif (0 <=numeric_value&&numeric_value <=2) {
2265+
config->import_time=numeric_value;
2266+
}
2267+
2268+
else {
2269+
return_PyStatus_ERR(
2270+
"-X importtime: numeric values other than 1 or 2 are "
2271+
"reserved for future use");
2272+
}
2273+
2274+
return_PyStatus_OK();
2275+
}
2276+
2277+
/* Configure `config->import_time` by checking -Ximporttime then the
2278+
* PYTHONPROFILEIMPORTTIME environment variable. Defaults to 0.
2279+
*/
2280+
staticPyStatus
2281+
config_read_import_time(PyConfig*config)
2282+
{
2283+
/* Check the -X option first. */
2284+
constwchar_t*xoption_value=NULL;
2285+
xoption_value=config_get_xoption_value(config,L"importtime");
2286+
if (xoption_value!=NULL) {
2287+
returnconfig_set_import_time(config,xoption_value);
2288+
}
2289+
2290+
/* If there's no -Ximporttime, look for ENV flag */
2291+
wchar_t*env_value=NULL;
2292+
/* `CONFIG_GET_ENV_DUP` requires dest to be initialized to `NULL`. */
2293+
PyStatusstatus=CONFIG_GET_ENV_DUP(config,&env_value,
2294+
L"PYTHONPROFILEIMPORTTIME",
2295+
"PYTHONPROFILEIMPORTTIME");
2296+
if (_PyStatus_EXCEPTION(status)) {
2297+
returnstatus;
2298+
}
2299+
if (env_value!=NULL) {
2300+
status=config_set_import_time(config,env_value);
2301+
PyMem_RawFree(env_value);
2302+
returnstatus;
2303+
}
2304+
2305+
return_PyStatus_OK();
2306+
}
22492307

22502308
staticPyStatus
22512309
config_read_complex_options(PyConfig*config)
@@ -2257,17 +2315,18 @@ config_read_complex_options(PyConfig *config)
22572315
config->faulthandler=1;
22582316
}
22592317
}
2260-
if (config_get_env(config,"PYTHONPROFILEIMPORTTIME")
2261-
||config_get_xoption(config,L"importtime")) {
2262-
config->import_time=1;
2263-
}
2264-
22652318
if (config_get_env(config,"PYTHONNODEBUGRANGES")
22662319
||config_get_xoption(config,L"no_debug_ranges")) {
22672320
config->code_debug_ranges=0;
22682321
}
22692322

22702323
PyStatusstatus;
2324+
2325+
status=config_read_import_time(config);
2326+
if (_PyStatus_EXCEPTION(status)) {
2327+
returnstatus;
2328+
}
2329+
22712330
if (config->tracemalloc<0) {
22722331
status=config_init_tracemalloc(config);
22732332
if (_PyStatus_EXCEPTION(status)) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp