view contrib/perf.py @ 17025:8ad08dcab7d9 stable

subrepo: support Git being named "git.cmd" on Windows (issue3173) Popen does not consider "foo.cmd" equivalent to "foo" on Windows. Unfortunately, the default MSYS Git installation installs only "git.cmd" into the path by default. This patch probes for both possible names on Windows.
author Benjamin Pollack <benjamin@bitquabit.com>
date Tue, 12 Jun 2012 09:31:04 -0400
parents e8d37b78acfb
children 525fdb738975
line wrap: on
line source

# perf.py - performance test routines
'''helper extension to measure performance'''

from mercurial import cmdutil, scmutil, util, match, commands
import time, os, sys

def timer(func, title=None):
    results = []
    begin = time.time()
    count = 0
    while True:
        ostart = os.times()
        cstart = time.time()
        r = func()
        cstop = time.time()
        ostop = os.times()
        count += 1
        a, b = ostart, ostop
        results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
        if cstop - begin > 3 and count >= 100:
            break
        if cstop - begin > 10 and count >= 3:
            break
    if title:
        sys.stderr.write("! %s\n" % title)
    if r:
        sys.stderr.write("! result: %s\n" % r)
    m = min(results)
    sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
                     % (m[0], m[1] + m[2], m[1], m[2], count))

def perfwalk(ui, repo, *pats):
    try:
        m = scmutil.match(repo[None], pats, {})
        timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
    except:
        try:
            m = scmutil.match(repo[None], pats, {})
            timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
        except:
            timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))

def perfstatus(ui, repo, *pats):
    #m = match.always(repo.root, repo.getcwd())
    #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False, False))))
    timer(lambda: sum(map(len, repo.status())))

def perfheads(ui, repo):
    timer(lambda: len(repo.changelog.headrevs()))

def perftags(ui, repo):
    import mercurial.changelog, mercurial.manifest
    def t():
        repo.changelog = mercurial.changelog.changelog(repo.sopener)
        repo.manifest = mercurial.manifest.manifest(repo.sopener)
        repo._tags = None
        return len(repo.tags())
    timer(t)

def perfdirstate(ui, repo):
    "a" in repo.dirstate
    def d():
        repo.dirstate.invalidate()
        "a" in repo.dirstate
    timer(d)

def perfdirstatedirs(ui, repo):
    "a" in repo.dirstate
    def d():
        "a" in repo.dirstate._dirs
        del repo.dirstate._dirs
    timer(d)

def perfmanifest(ui, repo):
    def d():
        t = repo.manifest.tip()
        m = repo.manifest.read(t)
        repo.manifest.mapcache = None
        repo.manifest._cache = None
    timer(d)

def perfchangeset(ui, repo, rev):
    n = repo[rev].node()
    def d():
        c = repo.changelog.read(n)
        #repo.changelog._cache = None
    timer(d)

def perfindex(ui, repo):
    import mercurial.revlog
    mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
    n = repo["tip"].node()
    def d():
        cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
        cl.rev(n)
    timer(d)

def perfstartup(ui, repo):
    cmd = sys.argv[0]
    def d():
        os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
    timer(d)

def perfparents(ui, repo):
    nl = [repo.changelog.node(i) for i in xrange(1000)]
    def d():
        for n in nl:
            repo.changelog.parents(n)
    timer(d)

def perflookup(ui, repo, rev):
    timer(lambda: len(repo.lookup(rev)))

def perfnodelookup(ui, repo, rev):
    import mercurial.revlog
    mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
    n = repo[rev].node()
    def d():
        cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
        cl.rev(n)
    timer(d)

def perfnodelookup(ui, repo, rev):
    import mercurial.revlog
    mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
    n = repo[rev].node()
    cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
    # behave somewhat consistently across internal API changes
    if util.safehasattr(cl, 'clearcaches'):
        clearcaches = cl.clearcaches
    elif util.safehasattr(cl, '_nodecache'):
        from mercurial.node import nullid, nullrev
        def clearcaches():
            cl._nodecache = {nullid: nullrev}
            cl._nodepos = None
    else:
        def clearcaches():
            pass
    def d():
        cl.rev(n)
        clearcaches()
    timer(d)

def perflog(ui, repo, **opts):
    ui.pushbuffer()
    timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
                               copies=opts.get('rename')))
    ui.popbuffer()

def perftemplating(ui, repo):
    ui.pushbuffer()
    timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
                               template='{date|shortdate} [{rev}:{node|short}]'
                               ' {author|person}: {desc|firstline}\n'))
    ui.popbuffer()

def perfcca(ui, repo):
    timer(lambda: scmutil.casecollisionauditor(ui, False, repo[None]))

def perffncacheload(ui, repo):
    from mercurial import scmutil, store
    s = store.store(set(['store','fncache']), repo.path, scmutil.opener)
    def d():
        s.fncache._load()
    timer(d)

def perffncachewrite(ui, repo):
    from mercurial import scmutil, store
    s = store.store(set(['store','fncache']), repo.path, scmutil.opener)
    s.fncache._load()
    def d():
        s.fncache._dirty = True
        s.fncache.write()
    timer(d)

def perfdiffwd(ui, repo):
    """Profile diff of working directory changes"""
    options = {
        'w': 'ignore_all_space',
        'b': 'ignore_space_change',
        'B': 'ignore_blank_lines',
        }

    for diffopt in ('', 'w', 'b', 'B', 'wB'):
        opts = dict((options[c], '1') for c in diffopt)
        def d():
            ui.pushbuffer()
            commands.diff(ui, repo, **opts)
            ui.popbuffer()
        title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
        timer(d, title)

def perfrevlog(ui, repo, file_, **opts):
    from mercurial import revlog
    dist = opts['dist']
    def d():
        r = revlog.revlog(lambda fn: open(fn, 'rb'), file_)
        for x in xrange(0, len(r), dist):
            r.revision(r.node(x))

    timer(d)

cmdtable = {
    'perfcca': (perfcca, []),
    'perffncacheload': (perffncacheload, []),
    'perffncachewrite': (perffncachewrite, []),
    'perflookup': (perflookup, []),
    'perfnodelookup': (perfnodelookup, []),
    'perfparents': (perfparents, []),
    'perfstartup': (perfstartup, []),
    'perfstatus': (perfstatus, []),
    'perfwalk': (perfwalk, []),
    'perfmanifest': (perfmanifest, []),
    'perfchangeset': (perfchangeset, []),
    'perfindex': (perfindex, []),
    'perfheads': (perfheads, []),
    'perftags': (perftags, []),
    'perfdirstate': (perfdirstate, []),
    'perfdirstatedirs': (perfdirstate, []),
    'perflog': (perflog,
                [('', 'rename', False, 'ask log to follow renames')]),
    'perftemplating': (perftemplating, []),
    'perfdiffwd': (perfdiffwd, []),
    'perfrevlog': (perfrevlog,
                   [('d', 'dist', 100, 'distance between the revisions')],
                   "[INDEXFILE]"),
}