Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
- --- a/mercurial/changegroup.py
- +++ b/mercurial/changegroup.py
- @@ -26,6 +26,7 @@ from . import (
- error,
- mdiff,
- phases,
- + tracing,
- util,
- )
- @@ -298,6 +299,7 @@ class cg1unpacker(object):
- trp = weakref.proxy(tr)
- # pull off the changeset group
- repo.ui.status(_("adding changesets\n"))
- + tracing.event('adding changesets', 'apply', 'B')
- clstart = len(cl)
- class prog(object):
- def __init__(self, step, total):
- @@ -324,11 +326,13 @@ class cg1unpacker(object):
- clend = len(cl)
- changesets = clend - clstart
- repo.ui.progress(_('changesets'), None)
- + tracing.event('adding changesets', 'apply', 'E')
- self.callback = None
- # pull off the manifest group
- repo.ui.status(_("adding manifests\n"))
- - self._unpackmanifests(repo, revmap, trp, prog, changesets)
- + with tracing.duration('adding manifests', 'apply'):
- + self._unpackmanifests(repo, revmap, trp, prog, changesets)
- needfiles = {}
- if repo.ui.configbool('server', 'validate', default=False):
- @@ -344,10 +348,11 @@ class cg1unpacker(object):
- # process the files
- repo.ui.status(_("adding file changes\n"))
- - newrevs, newfiles = _addchangegroupfiles(
- - repo, self, revmap, trp, efiles, needfiles)
- - revisions += newrevs
- - files += newfiles
- + with tracing.duration('adding file changes', 'apply'):
- + newrevs, newfiles = _addchangegroupfiles(
- + repo, self, revmap, trp, efiles, needfiles)
- + revisions += newrevs
- + files += newfiles
- dh = 0
- if oldheads:
- @@ -376,6 +381,7 @@ class cg1unpacker(object):
- hookargs['node_last'] = hex(cl.node(clend - 1))
- repo.hook('pretxnchangegroup', throw=True, **hookargs)
- + tracing.event('phases', 'apply', 'B')
- added = [cl.node(r) for r in xrange(clstart, clend)]
- publishing = repo.publishing()
- if srctype in ('push', 'serve'):
- @@ -401,6 +407,7 @@ class cg1unpacker(object):
- #
- # strip should not touch boundary at all
- phases.retractboundary(repo, tr, targetphase, added)
- + tracing.event('phases', 'apply', 'E')
- if changesets > 0:
- if srctype != 'strip':
- @@ -409,7 +416,8 @@ class cg1unpacker(object):
- # In other case we can safely update cache on
- # disk.
- repo.ui.debug('updating the branch cache\n')
- - branchmap.updatecache(repo.filtered('served'))
- + with tracing.duration('updating branch cache', 'apply'):
- + branchmap.updatecache(repo.filtered('served'))
- def runhooks():
- # These hooks run when the lock releases, not when the
- diff --git a/mercurial/commands.py b/mercurial/commands.py
- --- a/mercurial/commands.py
- +++ b/mercurial/commands.py
- @@ -65,6 +65,7 @@ from . import (
- streamclone,
- templatekw,
- templater,
- + tracing,
- ui as uimod,
- util,
- )
- @@ -4597,8 +4598,9 @@ def log(ui, repo, *pats, **opts):
- if opts.get('graph'):
- return cmdutil.graphlog(ui, repo, *pats, **opts)
- - revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
- - limit = cmdutil.loglimit(opts)
- + with tracing.duration('getlogrevs', 'log'):
- + revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
- + limit = cmdutil.loglimit(opts)
- count = 0
- getrenamed = None
- @@ -4609,6 +4611,7 @@ def log(ui, repo, *pats, **opts):
- getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
- displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
- + tracing.event('displayer', 'log', 'B')
- for rev in revs:
- if count == limit:
- break
- @@ -4627,6 +4630,7 @@ def log(ui, repo, *pats, **opts):
- displayer.show(ctx, copies=copies, matchfn=revmatchfn)
- if displayer.flush(ctx):
- count += 1
- + tracing.event('displayer', 'log', 'E')
- displayer.close()
- diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
- --- a/mercurial/dirstate.py
- +++ b/mercurial/dirstate.py
- @@ -23,6 +23,7 @@ from . import (
- pathutil,
- pycompat,
- scmutil,
- + tracing,
- util,
- )
- @@ -393,6 +394,7 @@ class dirstate(object):
- self._pendingmode = mode
- return fp
- + @tracing.call
- def _read(self):
- self._map = {}
- self._copymap = {}
- @@ -938,6 +940,7 @@ class dirstate(object):
- return results, dirsfound, dirsnotfound
- + @tracing.call
- def walk(self, match, subrepos, unknown, ignored, full=True):
- '''
- Walk recursively through the directory tree, finding all files
- @@ -1100,6 +1103,7 @@ class dirstate(object):
- results[nf()] = st
- return results
- + @tracing.call
- def status(self, match, subrepos, ignored, clean, unknown):
- '''Determine the status of the working copy relative to the
- dirstate and return a pair of (unsure, status), where status is of type
- diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
- --- a/mercurial/dispatch.py
- +++ b/mercurial/dispatch.py
- @@ -19,7 +19,6 @@ import sys
- import time
- import traceback
- -
- from .i18n import _
- from . import (
- @@ -42,6 +41,7 @@ from . import (
- templatefilters,
- templatekw,
- templater,
- + tracing,
- ui as uimod,
- util,
- )
- @@ -652,12 +652,18 @@ def _dispatch(req):
- if cwd:
- os.chdir(cwd[-1])
- + tracefile = _earlygetopt(['--trace'], args)
- + if tracefile:
- + tracing.setup(tracing.tracing(open(tracefile[-1], 'w')))
- + tracing.event('startup', 'startup', 'B')
- +
- rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
- path, lui = _getlocal(ui, rpath)
- # Configure extensions in phases: uisetup, extsetup, cmdtable, and
- # reposetup. Programs like TortoiseHg will call _dispatch several
- # times so we keep track of configured extensions in _loaded.
- + tracing.event('load extensions', 'extensions,startup', 'B')
- extensions.loadall(lui)
- exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
- # Propagate any changes to lui.__class__ by extensions
- @@ -671,9 +677,11 @@ def _dispatch(req):
- if extraobj is not None:
- getattr(loadermod, loadername)(ui, name, extraobj)
- _loaded.add(name)
- + tracing.event('load extensions', 'extensions,startup', 'E')
- # (reposetup is handled in hg.repository)
- + tracing.event('aliases', 'extensions,startup', 'B')
- # Side-effect of accessing is debugcommands module is guaranteed to be
- # imported and commands.table is populated.
- debugcommands.command
- @@ -683,6 +691,7 @@ def _dispatch(req):
- # All aliases and commands are completely defined, now.
- # Check abbreviation/ambiguity of shell alias.
- shellaliasfn = _checkshellalias(lui, ui, args)
- + tracing.event('aliases', 'extensions,startup', 'E')
- if shellaliasfn:
- with profiling.maybeprofile(lui):
- return shellaliasfn()
- @@ -692,6 +701,8 @@ def _dispatch(req):
- if fallback:
- encoding.fallbackencoding = fallback
- + tracing.event('options', 'startup', 'B')
- +
- fullargs = args
- cmd, func, args, options, cmdoptions = _parse(lui, args)
- @@ -755,6 +766,9 @@ def _dispatch(req):
- elif not cmd:
- return commands.help_(ui, 'shortlist')
- + tracing.event('options', 'startup', 'E')
- + tracing.event('reposetup', 'startup', 'B')
- +
- with profiling.maybeprofile(lui):
- repo = None
- cmdpats = args[:]
- @@ -802,14 +816,19 @@ def _dispatch(req):
- elif rpath:
- ui.warn(_("warning: --repository ignored\n"))
- + tracing.event('reposetup', 'startup', 'E')
- +
- msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
- ui.log("command", '%s\n', msg)
- strcmdopt = pycompat.strkwargs(cmdoptions)
- d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
- try:
- - return runcommand(lui, repo, cmd, fullargs, ui, options, d,
- - cmdpats, cmdoptions)
- + tracing.event('startup', 'startup', 'E')
- + with tracing.duration('run command ' + cmd, 'execution'):
- + return runcommand(lui, repo, cmd, fullargs, ui, options, d,
- + cmdpats, cmdoptions)
- finally:
- + tracing.close()
- if repo and repo != req.repo:
- repo.close()
- diff --git a/mercurial/extensions.py b/mercurial/extensions.py
- --- a/mercurial/extensions.py
- +++ b/mercurial/extensions.py
- @@ -19,6 +19,7 @@ from . import (
- cmdutil,
- error,
- pycompat,
- + tracing,
- util,
- )
- @@ -163,7 +164,8 @@ def loadall(ui):
- _disabledextensions[name] = path[1:]
- continue
- try:
- - load(ui, name, path)
- + with tracing.duration('load ' + name, 'extensions,startup'):
- + load(ui, name, path)
- except KeyboardInterrupt:
- raise
- except Exception as inst:
- diff --git a/mercurial/hook.py b/mercurial/hook.py
- --- a/mercurial/hook.py
- +++ b/mercurial/hook.py
- @@ -17,6 +17,7 @@ from . import (
- error,
- extensions,
- pycompat,
- + tracing,
- util,
- )
- @@ -188,19 +189,20 @@ def redirect(state):
- _redirect = state
- def hook(ui, repo, name, throw=False, **args):
- - if not ui.callhooks:
- - return False
- + with tracing.duration(name, 'hook'):
- + if not ui.callhooks:
- + return False
- - hooks = []
- - for hname, cmd in _allhooks(ui):
- - if hname.split('.')[0] == name and cmd:
- - hooks.append((hname, cmd))
- + hooks = []
- + for hname, cmd in _allhooks(ui):
- + if hname.split('.')[0] == name and cmd:
- + hooks.append((hname, cmd))
- - res = runhooks(ui, repo, name, hooks, throw=throw, **args)
- - r = False
- - for hname, cmd in hooks:
- - r = res[hname][0] or r
- - return r
- + res = runhooks(ui, repo, name, hooks, throw=throw, **args)
- + r = False
- + for hname, cmd in hooks:
- + r = res[hname][0] or r
- + return r
- def runhooks(ui, repo, name, hooks, throw=False, **args):
- res = {}
- diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
- --- a/mercurial/localrepo.py
- +++ b/mercurial/localrepo.py
- @@ -54,6 +54,7 @@ from . import (
- store,
- subrepo,
- tags as tagsmod,
- + tracing,
- transaction,
- util,
- )
- @@ -507,6 +508,7 @@ class localrepository(object):
- return store
- @storecache('00changelog.i')
- + @tracing.call
- def changelog(self):
- c = changelog.changelog(self.svfs)
- if 'HG_PENDING' in encoding.environ:
- @@ -522,10 +524,12 @@ class localrepository(object):
- return manifest.manifestrevlog(self.svfs)
- @storecache('00manifest.i')
- + @tracing.call
- def manifestlog(self):
- return manifest.manifestlog(self.svfs, self)
- @repofilecache('dirstate')
- + @tracing.call
- def dirstate(self):
- return dirstate.dirstate(self.vfs, self.ui, self.root,
- self._dirstatevalidate)
- @@ -1040,6 +1044,7 @@ class localrepository(object):
- idbase = "%.40f#%f" % (random.random(), time.time())
- txnid = 'TXN:' + hashlib.sha1(idbase).hexdigest()
- self.hook('pretxnopen', throw=True, txnname=desc, txnid=txnid)
- + tracing.event('txn-' + desc, 'transaction', 'B')
- self._writejournal(desc)
- renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
- @@ -1095,6 +1100,7 @@ class localrepository(object):
- def hook():
- reporef().hook('txnclose', throw=False, txnname=desc,
- **hookargs)
- + tracing.event('txn-' + desc, 'transaction', 'E')
- reporef()._afterlock(hook)
- tr.addfinalize('txnclose-hook', txnclosehook)
- def txnaborthook(tr2):
- @@ -1102,6 +1108,7 @@ class localrepository(object):
- """
- reporef().hook('txnabort', throw=False, txnname=desc,
- **tr2.hookargs)
- + tracing.event('txn-' + desc, 'transaction', 'E')
- tr.addabort('txnabort-hook', txnaborthook)
- # avoid eager cache invalidation. in-memory data should be identical
- # to stored data if transaction has no error.
- diff --git a/mercurial/match.py b/mercurial/match.py
- --- a/mercurial/match.py
- +++ b/mercurial/match.py
- @@ -15,11 +15,13 @@ from .i18n import _
- from . import (
- error,
- pathutil,
- + tracing,
- util,
- )
- propertycache = util.propertycache
- +@tracing.call
- def _rematcher(regex):
- '''compile the regexp with the best available regexp engine and return a
- matcher function'''
- @@ -550,6 +552,7 @@ def _regex(kind, pat, globsuffix):
- return '.*' + pat
- return _globre(pat) + globsuffix
- +@tracing.call
- def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root):
- '''Return regexp string and a matcher function for kindpats.
- globsuffix is appended to the regexp of globs.'''
- diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
- --- a/mercurial/obsolete.py
- +++ b/mercurial/obsolete.py
- @@ -79,6 +79,7 @@ from . import (
- node,
- parsers,
- phases,
- + tracing,
- util,
- )
- @@ -636,13 +637,15 @@ class obsstore(object):
- return self.add(transaction, markers)
- @propertycache
- + @tracing.call
- def _all(self):
- data = self.svfs.tryread('obsstore')
- if not data:
- return []
- self._version, markers = _readmarkers(data)
- markers = list(markers)
- - _checkinvalidmarkers(markers)
- + with tracing.duration('check invalid markers', 'repo'):
- + _checkinvalidmarkers(markers)
- return markers
- @propertycache
- diff --git a/mercurial/tracing.py b/mercurial/tracing.py
- new file mode 100644
- --- /dev/null
- +++ b/mercurial/tracing.py
- @@ -0,0 +1,122 @@
- +# tracing.py - performance tracing support
- +#
- +# Copyright (C) 2016 Facebook, Inc. <bryano@fb.com>
- +#
- +# This software may be used and distributed according to the terms of the
- +# GNU General Public License version 2 or any later version.
- +
- +from __future__ import absolute_import
- +
- +import contextlib
- +import inspect
- +import json
- +import os
- +
- +from . import (
- + util,
- + )
- +
- +_encode = None
- +
- +class tracing(object):
- + def __init__(self, fp):
- + global _encode
- + if _encode is None:
- + _encode = json.encoder.encode_basestring_ascii
- + self.lastcount = self.starttime = util.timer()
- + self.logfp = fp
- + self.pid = os.getpid()
- + self.logfp.write('[\n{"name":"tracing", "cat":"tracing", "ph":"B", '
- + '"pid":%d, "ts":0}' % (self.pid,))
- + self.threshold = 1e-3
- +
- + @contextlib.contextmanager
- + def duration(self, name, category, **kwargs):
- + start = util.timer()
- + try:
- + yield
- + finally:
- + end = util.timer()
- + if end - start >= self.threshold:
- + if kwargs:
- + args = ',\n "args":' + json.dumps(kwargs)
- + else:
- + args = ''
- + self.logfp.write(',\n{"name":%s, "cat":%s,\n "ph":"X", '
- + '"pid":%d, "ts":%r, "dur":%r%s}' %
- + (_encode(name), _encode(category), self.pid,
- + (start - self.starttime) * 1e6,
- + (end - start) * 1e6, args))
- +
- + def event(self, name, category, phase, timestamp=None, **kwargs):
- + if timestamp is None:
- + timestamp = util.timer()
- + if kwargs:
- + args = ',\n "args":' + json.dumps(kwargs)
- + else:
- + args = ''
- + self.logfp.write(',\n{"name":%s, "cat":%s,\n "ph":"%c", "pid":%d, '
- + '"ts":%r%s}' %
- + (_encode(name), _encode(category), phase, self.pid,
- + (timestamp - self.starttime) * 1e6, args))
- +
- + def progress(self, name, **kwargs):
- + timestamp = util.timer()
- + if timestamp - self.lastcount < 0.05:
- + return
- + self.lastcount = timestamp
- + self.logfp.write(',\n{"name":%s, "ph":"C", "pid":%d, "ts":%r,'
- + '\n "args":%s}' %
- + (_encode(name), self.pid,
- + (timestamp - self.starttime) * 1e6,
- + json.dumps(kwargs)))
- +
- + def forked(self):
- + self.pid = os.getpid()
- +
- + def close(self):
- + timestamp = util.timer()
- + self.logfp.write(',\n{"name":"tracing", "cat":"tracing",\n "ph":"E", '
- + '"pid":%d, "ts":%r}\n]\n' %
- + (self.pid, (timestamp - self.starttime) * 1e6))
- + self.logfp.close()
- +
- +@contextlib.contextmanager
- +def duration(name, category):
- + yield
- +
- +def event(name, category, phase, timestamp=None, **kwargs):
- + pass
- +
- +def progress(name, **kwargs):
- + pass
- +
- +def forked():
- + pass
- +
- +def close():
- + pass
- +
- +def setup(tr):
- + global duration, event, count, forked, close
- + duration = tr.duration
- + event = tr.event
- + count = tr.count
- + forked = tr.forked
- + close = tr.close
- +
- +def call(func):
- + funcname = [None]
- + def wrapped(*args, **kwargs):
- + fn = funcname[0]
- + if fn is None:
- + if inspect.ismethod(func):
- + fn = funcname[0] = '%s %s.%s' % (func.__name__,
- + func.__class__.__module__,
- + func.__class__.__name__)
- + else:
- + fn = funcname[0] = '%s %s' % (func.__name__, func.__module__)
- + with duration(fn, 'call'):
- + return func(*args, **kwargs)
- + wrapped.__name__ = func.__name__
- + return wrapped
- diff --git a/mercurial/ui.py b/mercurial/ui.py
- --- a/mercurial/ui.py
- +++ b/mercurial/ui.py
- @@ -29,6 +29,7 @@ from . import (
- progress,
- pycompat,
- scmutil,
- + tracing,
- util,
- )
- @@ -1150,7 +1151,10 @@ class ui(object):
- if self._progbar is not None:
- self._progbar.progress(topic, pos, item=item, unit=unit,
- total=total)
- - if pos is None or not self.configbool('progress', 'debug'):
- + if pos is None:
- + return
- + tracing.progress(topic, pos=pos)
- + if not self.configbool('progress', 'debug'):
- return
- if unit:
- diff --git a/mercurial/util.py b/mercurial/util.py
- --- a/mercurial/util.py
- +++ b/mercurial/util.py
- @@ -1203,8 +1203,10 @@ def checkwinfilename(path):
- if pycompat.osname == 'nt':
- checkosfilename = checkwinfilename
- + timer = time.clock
- else:
- checkosfilename = platform.checkosfilename
- + timer = time.time
- def makelock(info, pathname):
- try:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement