mercurial/profiling.py
author Matt Harbison <matt_harbison@yahoo.com>
Thu, 01 Mar 2018 11:37:00 -0500
branchstable
changeset 35834 fb278041df06
parent 34413 83dfbda40e67
child 36430 7b86aa31b004
permissions -rw-r--r--
subrepo: activate clone pooling to enable sharing with remote URLs This is the easiest way to ensure that repositories with remote subrepo references can share the subrepos, consistent with how local subrepos can be shared.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     1
# profiling.py - profiling functions
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     2
#
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     3
# Copyright 2016 Gregory Szorc <gregory.szorc@gmail.com>
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     4
#
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     7
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     8
from __future__ import absolute_import, print_function
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     9
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    10
import contextlib
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    11
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    12
from .i18n import _
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    13
from . import (
30820
6a70cf94d1b5 py3: replace pycompat.getenv with encoding.environ.get
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30667
diff changeset
    14
    encoding,
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    15
    error,
32455
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    16
    extensions,
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    17
    util,
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    18
)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    19
32455
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    20
def _loadprofiler(ui, profiler):
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    21
    """load profiler extension. return profile method, or None on failure"""
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    22
    extname = profiler
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    23
    extensions.loadall(ui, whitelist=[extname])
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    24
    try:
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    25
        mod = extensions.find(extname)
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    26
    except KeyError:
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    27
        return None
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    28
    else:
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    29
        return getattr(mod, 'profile', None)
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 30995
diff changeset
    30
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    31
@contextlib.contextmanager
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    32
def lsprofile(ui, fp):
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33197
diff changeset
    33
    format = ui.config('profiling', 'format')
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33197
diff changeset
    34
    field = ui.config('profiling', 'sort')
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33197
diff changeset
    35
    limit = ui.configint('profiling', 'limit')
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33197
diff changeset
    36
    climit = ui.configint('profiling', 'nested')
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    37
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    38
    if format not in ['text', 'kcachegrind']:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    39
        ui.warn(_("unrecognized profiling format '%s'"
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    40
                    " - Ignored\n") % format)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    41
        format = 'text'
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    42
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    43
    try:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    44
        from . import lsprof
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    45
    except ImportError:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    46
        raise error.Abort(_(
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    47
            'lsprof not available - install from '
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    48
            'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    49
    p = lsprof.Profiler()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    50
    p.enable(subcalls=True)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    51
    try:
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    52
        yield
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    53
    finally:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    54
        p.disable()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    55
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    56
        if format == 'kcachegrind':
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    57
            from . import lsprofcalltree
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    58
            calltree = lsprofcalltree.KCacheGrind(p)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    59
            calltree.output(fp)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    60
        else:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    61
            # format == 'text'
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    62
            stats = lsprof.Stats(p.getstats())
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    63
            stats.sort(field)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    64
            stats.pprint(limit=limit, file=fp, climit=climit)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    65
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    66
@contextlib.contextmanager
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    67
def flameprofile(ui, fp):
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    68
    try:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    69
        from flamegraph import flamegraph
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    70
    except ImportError:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    71
        raise error.Abort(_(
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    72
            'flamegraph not available - install from '
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    73
            'https://github.com/evanhempel/python-flamegraph'))
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    74
    # developer config: profiling.freq
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33197
diff changeset
    75
    freq = ui.configint('profiling', 'freq')
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    76
    filter_ = None
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    77
    collapse_recursion = True
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    78
    thread = flamegraph.ProfileThread(fp, 1.0 / freq,
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    79
                                      filter_, collapse_recursion)
30995
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30950
diff changeset
    80
    start_time = util.timer()
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    81
    try:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    82
        thread.start()
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    83
        yield
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    84
    finally:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    85
        thread.stop()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    86
        thread.join()
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    87
        print('Collected %d stack frames (%d unique) in %2.2f seconds.' % (
30995
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30950
diff changeset
    88
            util.timer() - start_time, thread.num_frames(),
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    89
            thread.num_frames(unique=True)))
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    90
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    91
@contextlib.contextmanager
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
    92
def statprofile(ui, fp):
30329
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
    93
    from . import statprof
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    94
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33197
diff changeset
    95
    freq = ui.configint('profiling', 'freq')
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    96
    if freq > 0:
29796
88d3c1ab03a7 profiling: don't error with statprof when profiling has already started
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29795
diff changeset
    97
        # Cannot reset when profiler is already active. So silently no-op.
88d3c1ab03a7 profiling: don't error with statprof when profiling has already started
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29795
diff changeset
    98
        if statprof.state.profile_level == 0:
88d3c1ab03a7 profiling: don't error with statprof when profiling has already started
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29795
diff changeset
    99
            statprof.reset(freq)
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   100
    else:
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   101
        ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   102
30329
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   103
    statprof.start(mechanism='thread')
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   104
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   105
    try:
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   106
        yield
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   107
    finally:
30329
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   108
        data = statprof.stop()
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   109
33499
0407a51b9d8c codemod: register core configitems using a script
Jun Wu <quark@fb.com>
parents: 33197
diff changeset
   110
        profformat = ui.config('profiling', 'statformat')
30329
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   111
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   112
        formats = {
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   113
            'byline': statprof.DisplayFormats.ByLine,
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   114
            'bymethod': statprof.DisplayFormats.ByMethod,
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   115
            'hotpath': statprof.DisplayFormats.Hotpath,
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   116
            'json': statprof.DisplayFormats.Json,
30950
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   117
            'chrome': statprof.DisplayFormats.Chrome,
30329
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   118
        }
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   119
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   120
        if profformat in formats:
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   121
            displayformat = formats[profformat]
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   122
        else:
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   123
            ui.warn(_('unknown profiler output format: %s\n') % profformat)
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   124
            displayformat = statprof.DisplayFormats.Hotpath
faf1b8923da2 profiling: use vendored statprof and upstream enhancements (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29796
diff changeset
   125
30950
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   126
        kwargs = {}
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   127
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   128
        def fraction(s):
32996
41b081ac2145 profiling: cope with configwith default value handling changes
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32869
diff changeset
   129
            if isinstance(s, (float, int)):
41b081ac2145 profiling: cope with configwith default value handling changes
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32869
diff changeset
   130
                return float(s)
30950
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   131
            if s.endswith('%'):
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   132
                v = float(s[:-1]) / 100
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   133
            else:
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   134
                v = float(s)
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   135
            if 0 <= v <= 1:
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   136
                return v
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   137
            raise ValueError(s)
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   138
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   139
        if profformat == 'chrome':
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   140
            showmin = ui.configwith(fraction, 'profiling', 'showmin', 0.005)
34411
fecea78ff2af configitems: register the 'profiling.showmax' config
Boris Feld <boris.feld@octobus.net>
parents: 33499
diff changeset
   141
            showmax = ui.configwith(fraction, 'profiling', 'showmax')
30950
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   142
            kwargs.update(minthreshold=showmin, maxthreshold=showmax)
32869
cb6436e051ca profiling: allow configuring minimum display threshold for hotpath
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32829
diff changeset
   143
        elif profformat == 'hotpath':
33197
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32996
diff changeset
   144
            # inconsistent config: profiling.showmin
32869
cb6436e051ca profiling: allow configuring minimum display threshold for hotpath
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32829
diff changeset
   145
            limit = ui.configwith(fraction, 'profiling', 'showmin', 0.05)
cb6436e051ca profiling: allow configuring minimum display threshold for hotpath
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32829
diff changeset
   146
            kwargs['limit'] = limit
30950
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   147
517bc1cd7033 profiling: add statprof support for Chrome trace viewer rendering
Bryan O'Sullivan <bryano@fb.com>
parents: 30820
diff changeset
   148
        statprof.display(fp, data=data, format=displayformat, **kwargs)
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   149
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   150
class profile(object):
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   151
    """Start profiling.
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   152
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   153
    Profiling is active when the context manager is active. When the context
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   154
    manager exits, profiling results will be written to the configured output.
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   155
    """
32805
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32804
diff changeset
   156
    def __init__(self, ui, enabled=True):
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   157
        self._ui = ui
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   158
        self._output = None
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   159
        self._fp = None
32824
2b0fc56840d0 profile: use explicit logic to control file closing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32823
diff changeset
   160
        self._fpdoclose = True
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   161
        self._profiler = None
32805
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32804
diff changeset
   162
        self._enabled = enabled
32804
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   163
        self._entered = False
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   164
        self._started = False
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   165
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   166
    def __enter__(self):
32804
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   167
        self._entered = True
32805
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32804
diff changeset
   168
        if self._enabled:
37ec8f24d912 profile: introduce a knob to control if the context is actually profiling
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32804
diff changeset
   169
            self.start()
32806
0ead06d54ffe profile: make the contextmanager object available to the callers
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32805
diff changeset
   170
        return self
32804
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   171
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   172
    def start(self):
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   173
        """Start profiling.
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   174
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   175
        The profiling will stop at the context exit.
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   176
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   177
        If the profiler was already started, this has no effect."""
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   178
        if not self._entered:
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   179
            raise error.ProgrammingError()
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   180
        if self._started:
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   181
            return
086c1ef0f666 profile: introduce a "start" method to the profile context
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32803
diff changeset
   182
        self._started = True
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   183
        profiler = encoding.environ.get('HGPROF')
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   184
        proffn = None
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   185
        if profiler is None:
34413
83dfbda40e67 configitems: register the 'profiling.type' config
Boris Feld <boris.feld@octobus.net>
parents: 34411
diff changeset
   186
            profiler = self._ui.config('profiling', 'type')
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   187
        if profiler not in ('ls', 'stat', 'flame'):
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   188
            # try load profiler from extension with the same name
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   189
            proffn = _loadprofiler(self._ui, profiler)
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   190
            if proffn is None:
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   191
                self._ui.warn(_("unrecognized profiler '%s' - ignored\n")
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   192
                              % profiler)
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   193
                profiler = 'stat'
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   194
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   195
        self._output = self._ui.config('profiling', 'output')
29792
2654a0aac80d profiling: move profiling code from dispatch.py (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   196
32827
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32826
diff changeset
   197
        try:
32826
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   198
            if self._output == 'blackbox':
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   199
                self._fp = util.stringio()
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   200
            elif self._output:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   201
                path = self._ui.expandpath(self._output)
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   202
                self._fp = open(path, 'wb')
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   203
            else:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   204
                self._fpdoclose = False
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   205
                self._fp = self._ui.ferr
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   206
32826
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   207
            if proffn is not None:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   208
                pass
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   209
            elif profiler == 'ls':
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   210
                proffn = lsprofile
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   211
            elif profiler == 'flame':
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   212
                proffn = flameprofile
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   213
            else:
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   214
                proffn = statprofile
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   215
32826
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   216
            self._profiler = proffn(self._ui, self._fp)
54b356d65079 profile: indent part of '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32825
diff changeset
   217
            self._profiler.__enter__()
32827
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32826
diff changeset
   218
        except: # re-raises
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32826
diff changeset
   219
            self._closefp()
336700745a5c profile: close 'fp' on error within '__enter__'
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32826
diff changeset
   220
            raise
29794
5d44197c208b profiling: make profiling functions context managers (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29792
diff changeset
   221
32803
4483696dacee profile: upgrade the "profile" context manager to a full class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32455
diff changeset
   222
    def __exit__(self, exception_type, exception_value, traceback):
32829
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32828
diff changeset
   223
        propagate = None
32828
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32827
diff changeset
   224
        if self._profiler is not None:
32829
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32828
diff changeset
   225
            propagate = self._profiler.__exit__(exception_type, exception_value,
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32828
diff changeset
   226
                                                traceback)
32828
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32827
diff changeset
   227
            if self._output == 'blackbox':
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32827
diff changeset
   228
                val = 'Profile:\n%s' % self._fp.getvalue()
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32827
diff changeset
   229
                # ui.log treats the input as a format string,
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32827
diff changeset
   230
                # so we need to escape any % signs.
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32827
diff changeset
   231
                val = val.replace('%', '%%')
062eb859d3ee profile: close 'fp' in all cases
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32827
diff changeset
   232
                self._ui.log('profile', val)
32825
3a4c677cbd6e profile: remove now useless indent
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32824
diff changeset
   233
        self._closefp()
32829
6675d23da748 profile: properly propagate exception from the sub-context manager
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32828
diff changeset
   234
        return propagate
32823
c0b2c8f25ad9 profiling: move 'fp' closing logic into its own function
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
   235
c0b2c8f25ad9 profiling: move 'fp' closing logic into its own function
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32808
diff changeset
   236
    def _closefp(self):
32824
2b0fc56840d0 profile: use explicit logic to control file closing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32823
diff changeset
   237
        if self._fpdoclose and self._fp is not None:
2b0fc56840d0 profile: use explicit logic to control file closing
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 32823
diff changeset
   238
            self._fp.close()