Skip to content

Commit

Permalink
Merge pull request #1253 from HaoZeke/usableProfleResults
Browse files Browse the repository at this point in the history
ENH: Return pstats.Stats for --profile
  • Loading branch information
mattip authored Apr 23, 2023
2 parents 997bb48 + f540100 commit d4692d0
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
3 changes: 2 additions & 1 deletion asv/commands/profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def setup_arguments(cls, subparsers):
help="""The benchmark to profile. Must be a
fully-specified benchmark name. For parameterized benchmark, it
must include the parameter combination to use, e.g.:
benchmark_name(param0, param1, ...)""")
benchmark_name\\(param0, param1, ...\\)""")
parser.add_argument(
'revision', nargs='?',
help="""The revision of the project to profile. May be a
Expand Down Expand Up @@ -214,5 +214,6 @@ def run(cls, conf, benchmark, revision=None, gui=None, output=None,
color_print('')
with temp_profile(profile_data) as profile_path:
stats = pstats.Stats(profile_path)
stats.strip_dirs() # Addresses gh-71
stats.sort_stats('cumulative')
stats.print_stats()
21 changes: 18 additions & 3 deletions asv/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import itertools
import hashlib
import datetime
import tempfile
import pstats

from . import environment, statistics, util
from .console import log
Expand Down Expand Up @@ -533,6 +535,14 @@ def add_result(self, benchmark, result,
profile_data = profile_data.decode('ascii')
self._profiles[benchmark_name] = profile_data

def _mk_pstats(self, bytedata):
fd, fpath = tempfile.mkstemp()
with os.fdopen(fd, 'wb') as hp:
hp.write(bytedata)
pstat = pstats.Stats(fpath)
os.remove(fpath)
return pstat

def get_profile(self, benchmark_name):
"""
Get the profile data for the given benchmark name.
Expand All @@ -544,13 +554,18 @@ def get_profile(self, benchmark_name):
Returns
-------
profile_data : bytes
Raw profile data
profile_data : pstats.Stats
Profile data
"""
profile_data = self._profiles[benchmark_name]
profile_data = profile_data.encode('ascii')
return zlib.decompress(base64.b64decode(profile_data))
profile_bytes = zlib.decompress(base64.b64decode(profile_data))
return profile_bytes

def get_profile_stats(self, benchmark_name):
profile_bytes = self.get_profile(benchmark_name)
return self._mk_pstats(profile_bytes)

def has_profile(self, benchmark_name):
"""
Expand Down
19 changes: 19 additions & 0 deletions docs/source/using.rst
Original file line number Diff line number Diff line change
Expand Up @@ -553,8 +553,27 @@ the ``--gui=runsnake`` to ``asv profile``, the profile is collected
You can also get the raw profiling data by using the ``--output``
argument to ``asv profile``.

.. note::

Since the method name is passed as a regex, parenthesis need to be escaped, e.g.
``asv profile 'benchmarks.MyBench.time_sort\(500\)' HEAD --gui snakeviz``

See :ref:`cmd-asv-profile` for more options.

To extract information from ``--profile`` runs of ``asv``::

$ python
import asv
results_asv = asv.results.iter_results(".asv")
res_objects = list(results_asv)
prof_data = res_objects[0].get_profile_stats('benchmarks.MyBench.time_sort')
prof_data.strip_dirs() # Remove machine specific info
prof_data.sort_stats('cumulative').print_stats()

Where different benchmarks may be used. A specific ``json`` may also be loaded
directly with ``asv.results.Results.load(<json_path>)``, after which
``get_profile_stats`` can be used.

.. _comparing:

Comparing the benchmarking results for two revisions
Expand Down

0 comments on commit d4692d0

Please sign in to comment.