bpo-32512: Add -m option to profile for profiling modules (#5132)
The new option in the CLI of the profile module allow to profile executable modules. This change follows the same implementation as the one already present in `cProfile`. As the argument is now present on both modules, move the tests to the common test case to be run with profile as well.
This commit is contained in:
parent
2810dd7be9
commit
ad1a25f499
|
@ -120,8 +120,8 @@ results to a file by specifying a filename to the :func:`run` function::
|
||||||
The :class:`pstats.Stats` class reads profile results from a file and formats
|
The :class:`pstats.Stats` class reads profile results from a file and formats
|
||||||
them in various ways.
|
them in various ways.
|
||||||
|
|
||||||
The file :mod:`cProfile` can also be invoked as a script to profile another
|
The files :mod:`cProfile` and :mod:`profile` can also be invoked as a script to
|
||||||
script. For example::
|
profile another script. For example::
|
||||||
|
|
||||||
python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)
|
python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)
|
||||||
|
|
||||||
|
@ -133,7 +133,10 @@ the output by. This only applies when ``-o`` is not supplied.
|
||||||
``-m`` specifies that a module is being profiled instead of a script.
|
``-m`` specifies that a module is being profiled instead of a script.
|
||||||
|
|
||||||
.. versionadded:: 3.7
|
.. versionadded:: 3.7
|
||||||
Added the ``-m`` option.
|
Added the ``-m`` option to :mod:`cProfile`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.8
|
||||||
|
Added the ``-m`` option to :mod:`profile`.
|
||||||
|
|
||||||
The :mod:`pstats` module's :class:`~pstats.Stats` class has a variety of methods
|
The :mod:`pstats` module's :class:`~pstats.Stats` class has a variety of methods
|
||||||
for manipulating and printing the data saved into a profile results file::
|
for manipulating and printing the data saved into a profile results file::
|
||||||
|
|
|
@ -553,11 +553,13 @@ def main():
|
||||||
import os
|
import os
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
usage = "profile.py [-o output_file_path] [-s sort] scriptfile [arg] ..."
|
usage = "profile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
|
||||||
parser = OptionParser(usage=usage)
|
parser = OptionParser(usage=usage)
|
||||||
parser.allow_interspersed_args = False
|
parser.allow_interspersed_args = False
|
||||||
parser.add_option('-o', '--outfile', dest="outfile",
|
parser.add_option('-o', '--outfile', dest="outfile",
|
||||||
help="Save stats to <outfile>", default=None)
|
help="Save stats to <outfile>", default=None)
|
||||||
|
parser.add_option('-m', dest="module", action="store_true",
|
||||||
|
help="Profile a library module.", default=False)
|
||||||
parser.add_option('-s', '--sort', dest="sort",
|
parser.add_option('-s', '--sort', dest="sort",
|
||||||
help="Sort order when printing to stdout, based on pstats.Stats class",
|
help="Sort order when printing to stdout, based on pstats.Stats class",
|
||||||
default=-1)
|
default=-1)
|
||||||
|
@ -570,16 +572,24 @@ def main():
|
||||||
sys.argv[:] = args
|
sys.argv[:] = args
|
||||||
|
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
progname = args[0]
|
if options.module:
|
||||||
sys.path.insert(0, os.path.dirname(progname))
|
import runpy
|
||||||
with open(progname, 'rb') as fp:
|
code = "run_module(modname, run_name='__main__')"
|
||||||
code = compile(fp.read(), progname, 'exec')
|
globs = {
|
||||||
globs = {
|
'run_module': runpy.run_module,
|
||||||
'__file__': progname,
|
'modname': args[0]
|
||||||
'__name__': '__main__',
|
}
|
||||||
'__package__': None,
|
else:
|
||||||
'__cached__': None,
|
progname = args[0]
|
||||||
}
|
sys.path.insert(0, os.path.dirname(progname))
|
||||||
|
with open(progname, 'rb') as fp:
|
||||||
|
code = compile(fp.read(), progname, 'exec')
|
||||||
|
globs = {
|
||||||
|
'__file__': progname,
|
||||||
|
'__name__': '__main__',
|
||||||
|
'__package__': None,
|
||||||
|
'__cached__': None,
|
||||||
|
}
|
||||||
runctx(code, globs, None, options.outfile, options.sort)
|
runctx(code, globs, None, options.outfile, options.sort)
|
||||||
else:
|
else:
|
||||||
parser.print_usage()
|
parser.print_usage()
|
||||||
|
|
|
@ -37,19 +37,6 @@ class CProfileTest(ProfileTest):
|
||||||
finally:
|
finally:
|
||||||
unlink(TESTFN)
|
unlink(TESTFN)
|
||||||
|
|
||||||
# Issue 21862
|
|
||||||
def test_module_path_option(self):
|
|
||||||
# Test -m switch with modules
|
|
||||||
|
|
||||||
# Test that -m switch needs an argument
|
|
||||||
assert_python_failure('-m', 'cProfile', '-m')
|
|
||||||
|
|
||||||
# Test failure for not-existent module
|
|
||||||
assert_python_failure('-m', 'cProfile', '-m', 'random_module_xyz')
|
|
||||||
|
|
||||||
# Test successful run
|
|
||||||
assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1')
|
|
||||||
|
|
||||||
def test_profile_enable_disable(self):
|
def test_profile_enable_disable(self):
|
||||||
prof = self.profilerclass()
|
prof = self.profilerclass()
|
||||||
# Make sure we clean ourselves up if the test fails for some reason.
|
# Make sure we clean ourselves up if the test fails for some reason.
|
||||||
|
|
|
@ -11,6 +11,7 @@ from contextlib import contextmanager
|
||||||
|
|
||||||
import profile
|
import profile
|
||||||
from test.profilee import testfunc, timer
|
from test.profilee import testfunc, timer
|
||||||
|
from test.support.script_helper import assert_python_failure, assert_python_ok
|
||||||
|
|
||||||
|
|
||||||
class ProfileTest(unittest.TestCase):
|
class ProfileTest(unittest.TestCase):
|
||||||
|
@ -98,6 +99,18 @@ class ProfileTest(unittest.TestCase):
|
||||||
filename=TESTFN)
|
filename=TESTFN)
|
||||||
self.assertTrue(os.path.exists(TESTFN))
|
self.assertTrue(os.path.exists(TESTFN))
|
||||||
|
|
||||||
|
def test_run_profile_as_module(self):
|
||||||
|
# Test that -m switch needs an argument
|
||||||
|
assert_python_failure('-m', self.profilermodule.__name__, '-m')
|
||||||
|
|
||||||
|
# Test failure for not-existent module
|
||||||
|
assert_python_failure('-m', self.profilermodule.__name__,
|
||||||
|
'-m', 'random_module_xyz')
|
||||||
|
|
||||||
|
# Test successful run
|
||||||
|
assert_python_ok('-m', self.profilermodule.__name__,
|
||||||
|
'-m', 'timeit', '-n', '1')
|
||||||
|
|
||||||
|
|
||||||
def regenerate_expected_output(filename, cls):
|
def regenerate_expected_output(filename, cls):
|
||||||
filename = filename.rstrip('co')
|
filename = filename.rstrip('co')
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
:mod:`profile` CLI accepts `-m module_name` as an alternative to
|
||||||
|
script path.
|
Loading…
Reference in New Issue