Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
863b1e4d
Commit
863b1e4d
authored
Jan 25, 2018
by
mwidjaja
Committed by
Ethan Furman
Jan 25, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-29237: Create enum for pstats sorting options (GH-5103)
parent
4666ec59
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
144 additions
and
61 deletions
+144
-61
Doc/library/profile.rst
Doc/library/profile.rst
+62
-53
Lib/pstats.py
Lib/pstats.py
+38
-8
Lib/test/test_pstats.py
Lib/test/test_pstats.py
+42
-0
Misc/ACKS
Misc/ACKS
+1
-0
Misc/NEWS.d/next/Library/2018-01-04-14-45-33.bpo-29237.zenYA6.rst
...S.d/next/Library/2018-01-04-14-45-33.bpo-29237.zenYA6.rst
+1
-0
No files found.
Doc/library/profile.rst
View file @
863b1e4d
...
@@ -139,6 +139,7 @@ The :mod:`pstats` module's :class:`~pstats.Stats` class has a variety of methods
...
@@ -139,6 +139,7 @@ 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::
import pstats
import pstats
from pstats import SortKey
p = pstats.Stats('restats')
p = pstats.Stats('restats')
p.strip_dirs().sort_stats(-1).print_stats()
p.strip_dirs().sort_stats(-1).print_stats()
...
@@ -148,14 +149,14 @@ entries according to the standard module/line/name string that is printed. The
...
@@ -148,14 +149,14 @@ entries according to the standard module/line/name string that is printed. The
:meth:`~pstats.Stats.print_stats` method printed out all the statistics. You
:meth:`~pstats.Stats.print_stats` method printed out all the statistics. You
might try the following sort calls::
might try the following sort calls::
p.sort_stats(
'name'
)
p.sort_stats(
SortKey.NAME
)
p.print_stats()
p.print_stats()
The first call will actually sort the list by function name, and the second call
The first call will actually sort the list by function name, and the second call
will print out the statistics. The following are some interesting calls to
will print out the statistics. The following are some interesting calls to
experiment with::
experiment with::
p.sort_stats(
'cumulative'
).print_stats(10)
p.sort_stats(
SortKey.CUMULATIVE
).print_stats(10)
This sorts the profile by cumulative time in a function, and then only prints
This sorts the profile by cumulative time in a function, and then only prints
the ten most significant lines. If you want to understand what algorithms are
the ten most significant lines. If you want to understand what algorithms are
...
@@ -164,20 +165,20 @@ taking time, the above line is what you would use.
...
@@ -164,20 +165,20 @@ taking time, the above line is what you would use.
If you were looking to see what functions were looping a lot, and taking a lot
If you were looking to see what functions were looping a lot, and taking a lot
of time, you would do::
of time, you would do::
p.sort_stats(
'time'
).print_stats(10)
p.sort_stats(
SortKey.TIME
).print_stats(10)
to sort according to time spent within each function, and then print the
to sort according to time spent within each function, and then print the
statistics for the top ten functions.
statistics for the top ten functions.
You might also try::
You might also try::
p.sort_stats(
'file'
).print_stats('__init__')
p.sort_stats(
SortKey.FILENAME
).print_stats('__init__')
This will sort all the statistics by file name, and then print out statistics
This will sort all the statistics by file name, and then print out statistics
for only the class init methods (since they are spelled with ``__init__`` in
for only the class init methods (since they are spelled with ``__init__`` in
them). As one final example, you could try::
them). As one final example, you could try::
p.sort_stats(
'time', 'cumulative'
).print_stats(.5, 'init')
p.sort_stats(
SortKey.TIME, SortKey.CUMULATIVE
).print_stats(.5, 'init')
This line sorts statistics with a primary key of time, and a secondary key of
This line sorts statistics with a primary key of time, and a secondary key of
cumulative time, and then prints out some of the statistics. To be specific, the
cumulative time, and then prints out some of the statistics. To be specific, the
...
@@ -250,12 +251,13 @@ functions:
...
@@ -250,12 +251,13 @@ functions:
without writing the profile data to a file::
without writing the profile data to a file::
import cProfile, pstats, io
import cProfile, pstats, io
from pstats import SortKey
pr = cProfile.Profile()
pr = cProfile.Profile()
pr.enable()
pr.enable()
# ... do something ...
# ... do something ...
pr.disable()
pr.disable()
s = io.StringIO()
s = io.StringIO()
sortby =
'cumulative'
sortby =
SortKey.CUMULATIVE
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
ps.print_stats()
print(s.getvalue())
print(s.getvalue())
...
@@ -361,60 +363,65 @@ Analysis of the profiler data is done using the :class:`~pstats.Stats` class.
...
@@ -361,60 +363,65 @@ Analysis of the profiler data is done using the :class:`~pstats.Stats` class.
.. method:: sort_stats(*keys)
.. method:: sort_stats(*keys)
This method modifies the :class:`Stats` object by sorting it according to
This method modifies the :class:`Stats` object by sorting it according to
the supplied criteria. The argument is typically a string identifying the
the supplied criteria. The argument can be either a string or a SortKey
basis of a sort (example: ``'time'`` or ``'name'``).
enum identifying the basis of a sort (example: ``'time'``, ``'name'``,
``SortKey.TIME`` or ``SortKey.NAME``). The SortKey enums argument have
advantage over the string argument in that it is more robust and less
error prone.
When more than one key is provided, then additional keys are used as
When more than one key is provided, then additional keys are used as
secondary criteria when there is equality in all keys selected before
secondary criteria when there is equality in all keys selected before
them. For example, ``sort_stats('name', 'file')`` will sort all the
them. For example, ``sort_stats(SortKey.NAME, SortKey.FILE)`` will sort
entries according to their function name, and resolve all ties (identical
all the entries according to their function name, and resolve all ties
function names) by sorting by file name.
(identical function names) by sorting by file name.
Abbreviations can be used for any key names, as long as the abbreviation
For the string argument, abbreviations can be used for any key names, as
is unambiguous. The following are the keys currently defined:
long as the abbreviation is unambiguous.
+------------------+----------------------+
The following are the valid string and SortKey:
| Valid Arg | Meaning |
+==================+======================+
+------------------+---------------------+----------------------+
| ``'calls'`` | call count |
| Valid String Arg | Valid enum Arg | Meaning |
+------------------+----------------------+
+==================+=====================+======================+
| ``'cumulative'`` | cumulative time |
| ``'calls'`` | SortKey.CALLS | call count |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'cumtime'`` | cumulative time |
| ``'cumulative'`` | SortKey.CUMULATIVE | cumulative time |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'file'`` | file name |
| ``'cumtime'`` | N/A | cumulative time |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'filename'`` | file name |
| ``'file'`` | N/A | file name |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'module'`` | file name |
| ``'filename'`` | SortKey.FILENAME | file name |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'ncalls'`` | call count |
| ``'module'`` | N/A | file name |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'pcalls'`` | primitive call count |
| ``'ncalls'`` | N/A | call count |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'line'`` | line number |
| ``'pcalls'`` | SortKey.PCALLS | primitive call count |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'name'`` | function name |
| ``'line'`` | SortKey.LINE | line number |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'nfl'`` | name/file/line |
| ``'name'`` | SortKey.NAME | function name |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'stdname'`` | standard name |
| ``'nfl'`` | SortKey.NFL | name/file/line |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'time'`` | internal time |
| ``'stdname'`` | SortKey.STDNAME | standard name |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'tottime'`` | internal time |
| ``'time'`` | SortKey.TIME | internal time |
+------------------+----------------------+
+------------------+---------------------+----------------------+
| ``'tottime'`` | N/A | internal time |
+------------------+---------------------+----------------------+
Note that all sorts on statistics are in descending order (placing most
Note that all sorts on statistics are in descending order (placing most
time consuming items first), where as name, file, and line number searches
time consuming items first), where as name, file, and line number searches
are in ascending order (alphabetical). The subtle distinction between
are in ascending order (alphabetical). The subtle distinction between
``
'nfl'`` and ``'stdname'`` is that the standard name is a sort of the
``
SortKey.NFL`` and ``SortKey.STDNAME`` is that the standard name is a
name as printed, which means that the embedded line numbers get compared
sort of the name as printed, which means that the embedded line numbers
in an odd way. For example, lines 3, 20, and 40 would (if the file names
get compared in an odd way. For example, lines 3, 20, and 40 would (if
were the same) appear in the string order 20, 3 and 40. In contrast,
the file names were the same) appear in the string order 20, 3 and 40.
``'nfl'`` does a numeric compare of the line numbers. In fact,
In contrast, ``SortKey.NFL`` does a numeric compare of the line numbers.
``sort_stats('nfl')`` is the same as ``sort_stats('name', 'file',
In fact, ``sort_stats(SortKey.NFL)`` is the same as
'line'
)``.
``sort_stats(SortKey.NAME, SortKey.FILENAME, SortKey.LINE
)``.
For backward-compatibility reasons, the numeric arguments ``-1``, ``0``,
For backward-compatibility reasons, the numeric arguments ``-1``, ``0``,
``1``, and ``2`` are permitted. They are interpreted as ``'stdname'``,
``1``, and ``2`` are permitted. They are interpreted as ``'stdname'``,
...
@@ -424,6 +431,8 @@ Analysis of the profiler data is done using the :class:`~pstats.Stats` class.
...
@@ -424,6 +431,8 @@ Analysis of the profiler data is done using the :class:`~pstats.Stats` class.
.. For compatibility with the old profiler.
.. For compatibility with the old profiler.
.. versionadded:: 3.7
Added the SortKey enum.
.. method:: reverse_order()
.. method:: reverse_order()
...
...
Lib/pstats.py
View file @
863b1e4d
...
@@ -25,9 +25,32 @@ import os
...
@@ -25,9 +25,32 @@ import os
import
time
import
time
import
marshal
import
marshal
import
re
import
re
from
enum
import
Enum
from
functools
import
cmp_to_key
from
functools
import
cmp_to_key
__all__
=
[
"Stats"
]
__all__
=
[
"Stats"
,
"SortKey"
]
class
SortKey
(
str
,
Enum
):
CALLS
=
'calls'
,
'ncalls'
CUMULATIVE
=
'cumulative'
,
'cumtime'
FILENAME
=
'filename'
,
'module'
LINE
=
'line'
NAME
=
'name'
NFL
=
'nfl'
PCALLS
=
'pcalls'
STDNAME
=
'stdname'
TIME
=
'time'
,
'tottime'
def
__new__
(
cls
,
*
values
):
obj
=
str
.
__new__
(
cls
)
obj
.
_value_
=
values
[
0
]
for
other_value
in
values
[
1
:]:
cls
.
_value2member_map_
[
other_value
]
=
obj
obj
.
_all_values
=
values
return
obj
class
Stats
:
class
Stats
:
"""This class is used for creating reports from data generated by the
"""This class is used for creating reports from data generated by the
...
@@ -49,13 +72,14 @@ class Stats:
...
@@ -49,13 +72,14 @@ class Stats:
The sort_stats() method now processes some additional options (i.e., in
The sort_stats() method now processes some additional options (i.e., in
addition to the old -1, 0, 1, or 2 that are respectively interpreted as
addition to the old -1, 0, 1, or 2 that are respectively interpreted as
'stdname', 'calls', 'time', and 'cumulative'). It takes an arbitrary number
'stdname', 'calls', 'time', and 'cumulative'). It takes either an
of quoted strings to select the sort order.
arbitrary number of quoted strings or SortKey enum to select the sort
order.
For example sort_stats('time', 'name')
sorts on the major key of 'internal
For example sort_stats('time', 'name')
or sort_stats(SortKey.TIME,
function time', and on the minor key of 'the name of the function'. Look at
SortKey.NAME) sorts on the major key of 'internal function time', and on
the
two tables in sort_stats() and get_sort_arg_defs(self) for more
the
minor key of 'the name of the function'. Look at the two tables in
examples.
sort_stats() and get_sort_arg_defs(self) for more
examples.
All methods return self, so you can string together commands like:
All methods return self, so you can string together commands like:
Stats('foo', 'goo').strip_dirs().sort_stats('calls').
\
Stats('foo', 'goo').strip_dirs().sort_stats('calls').
\
...
@@ -161,7 +185,6 @@ class Stats:
...
@@ -161,7 +185,6 @@ class Stats:
"ncalls"
:
(((
1
,
-
1
),
),
"call count"
),
"ncalls"
:
(((
1
,
-
1
),
),
"call count"
),
"cumtime"
:
(((
3
,
-
1
),
),
"cumulative time"
),
"cumtime"
:
(((
3
,
-
1
),
),
"cumulative time"
),
"cumulative"
:
(((
3
,
-
1
),
),
"cumulative time"
),
"cumulative"
:
(((
3
,
-
1
),
),
"cumulative time"
),
"file"
:
(((
4
,
1
),
),
"file name"
),
"filename"
:
(((
4
,
1
),
),
"file name"
),
"filename"
:
(((
4
,
1
),
),
"file name"
),
"line"
:
(((
5
,
1
),
),
"line number"
),
"line"
:
(((
5
,
1
),
),
"line number"
),
"module"
:
(((
4
,
1
),
),
"file name"
),
"module"
:
(((
4
,
1
),
),
"file name"
),
...
@@ -202,12 +225,19 @@ class Stats:
...
@@ -202,12 +225,19 @@ class Stats:
0
:
"calls"
,
0
:
"calls"
,
1
:
"time"
,
1
:
"time"
,
2
:
"cumulative"
}[
field
[
0
]]
]
2
:
"cumulative"
}[
field
[
0
]]
]
elif
len
(
field
)
>=
2
:
for
arg
in
field
[
1
:]:
if
type
(
arg
)
!=
type
(
field
[
0
]):
raise
TypeError
(
"Can't have mixed argument type"
)
sort_arg_defs
=
self
.
get_sort_arg_defs
()
sort_arg_defs
=
self
.
get_sort_arg_defs
()
sort_tuple
=
()
sort_tuple
=
()
self
.
sort_type
=
""
self
.
sort_type
=
""
connector
=
""
connector
=
""
for
word
in
field
:
for
word
in
field
:
if
isinstance
(
word
,
SortKey
):
word
=
word
.
value
sort_tuple
=
sort_tuple
+
sort_arg_defs
[
word
][
0
]
sort_tuple
=
sort_tuple
+
sort_arg_defs
[
word
][
0
]
self
.
sort_type
+=
connector
+
sort_arg_defs
[
word
][
1
]
self
.
sort_type
+=
connector
+
sort_arg_defs
[
word
][
1
]
connector
=
", "
connector
=
", "
...
...
Lib/test/test_pstats.py
View file @
863b1e4d
...
@@ -2,6 +2,7 @@ import unittest
...
@@ -2,6 +2,7 @@ import unittest
from
test
import
support
from
test
import
support
from
io
import
StringIO
from
io
import
StringIO
import
pstats
import
pstats
from
pstats
import
SortKey
...
@@ -33,6 +34,47 @@ class StatsTestCase(unittest.TestCase):
...
@@ -33,6 +34,47 @@ class StatsTestCase(unittest.TestCase):
stats
=
pstats
.
Stats
(
stream
=
stream
)
stats
=
pstats
.
Stats
(
stream
=
stream
)
stats
.
add
(
self
.
stats
,
self
.
stats
)
stats
.
add
(
self
.
stats
,
self
.
stats
)
def
test_sort_stats_int
(
self
):
valid_args
=
{
-
1
:
'stdname'
,
0
:
'calls'
,
1
:
'time'
,
2
:
'cumulative'
}
for
arg_int
,
arg_str
in
valid_args
.
items
():
self
.
stats
.
sort_stats
(
arg_int
)
self
.
assertEqual
(
self
.
stats
.
sort_type
,
self
.
stats
.
sort_arg_dict_default
[
arg_str
][
-
1
])
def
test_sort_stats_string
(
self
):
for
sort_name
in
[
'calls'
,
'ncalls'
,
'cumtime'
,
'cumulative'
,
'filename'
,
'line'
,
'module'
,
'name'
,
'nfl'
,
'pcalls'
,
'stdname'
,
'time'
,
'tottime'
]:
self
.
stats
.
sort_stats
(
sort_name
)
self
.
assertEqual
(
self
.
stats
.
sort_type
,
self
.
stats
.
sort_arg_dict_default
[
sort_name
][
-
1
])
def
test_sort_stats_partial
(
self
):
sortkey
=
'filename'
for
sort_name
in
[
'f'
,
'fi'
,
'fil'
,
'file'
,
'filen'
,
'filena'
,
'filenam'
,
'filename'
]:
self
.
stats
.
sort_stats
(
sort_name
)
self
.
assertEqual
(
self
.
stats
.
sort_type
,
self
.
stats
.
sort_arg_dict_default
[
sortkey
][
-
1
])
def
test_sort_stats_enum
(
self
):
for
member
in
SortKey
:
self
.
stats
.
sort_stats
(
member
)
self
.
assertEqual
(
self
.
stats
.
sort_type
,
self
.
stats
.
sort_arg_dict_default
[
member
.
value
][
-
1
])
def
test_sort_starts_mix
(
self
):
self
.
assertRaises
(
TypeError
,
self
.
stats
.
sort_stats
,
'calls'
,
SortKey
.
TIME
)
self
.
assertRaises
(
TypeError
,
self
.
stats
.
sort_stats
,
SortKey
.
TIME
,
'calls'
)
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
unittest
.
main
()
unittest
.
main
()
Misc/ACKS
View file @
863b1e4d
...
@@ -1706,6 +1706,7 @@ Jeff Wheeler
...
@@ -1706,6 +1706,7 @@ Jeff Wheeler
Christopher White
Christopher White
David White
David White
Mats Wichmann
Mats Wichmann
Marcel Widjaja
Truida Wiedijk
Truida Wiedijk
Felix Wiemann
Felix Wiemann
Gerry Wiener
Gerry Wiener
...
...
Misc/NEWS.d/next/Library/2018-01-04-14-45-33.bpo-29237.zenYA6.rst
0 → 100644
View file @
863b1e4d
Create enum for pstats sorting options
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment