contrib/benchmarks/__init__.py
changeset 30406 cff0f5926797
child 30559 d83ca854fa21
equal deleted inserted replaced
30405:e77e8876886f 30406:cff0f5926797
       
     1 # __init__.py - asv benchmark suite
       
     2 #
       
     3 # Copyright 2016 Logilab SA <contact@logilab.fr>
       
     4 #
       
     5 # This software may be used and distributed according to the terms of the
       
     6 # GNU General Public License version 2 or any later version.
       
     7 
       
     8 '''ASV (https://asv.readthedocs.io) benchmark suite
       
     9 
       
    10 Benchmark are parameterized against reference repositories found in the
       
    11 directory pointed by the REPOS_DIR environment variable.
       
    12 
       
    13 Invocation example:
       
    14 
       
    15     $ export REPOS_DIR=~/hgperf/repos
       
    16     # run suite on given revision
       
    17     $ asv --config contrib/asv.conf.json run REV
       
    18     # run suite on new changesets found in stable and default branch
       
    19     $ asv --config contrib/asv.conf.json run NEW
       
    20     # display a comparative result table of benchmark results between two given
       
    21     # revisions
       
    22     $ asv --config contrib/asv.conf.json compare REV1 REV2
       
    23     # compute regression detection and generate ASV static website
       
    24     $ asv --config contrib/asv.conf.json publish
       
    25     # serve the static website
       
    26     $ asv --config contrib/asv.conf.json preview
       
    27 '''
       
    28 
       
    29 from __future__ import absolute_import
       
    30 
       
    31 import functools
       
    32 import os
       
    33 import re
       
    34 
       
    35 from mercurial import (
       
    36     extensions,
       
    37     hg,
       
    38     ui as uimod,
       
    39 )
       
    40 
       
    41 basedir = os.path.abspath(os.path.join(os.path.dirname(__file__),
       
    42                           os.path.pardir, os.path.pardir))
       
    43 reposdir = os.environ['REPOS_DIR']
       
    44 reposnames = [name for name in os.listdir(reposdir)
       
    45               if os.path.isdir(os.path.join(reposdir, name, ".hg"))]
       
    46 if not reposnames:
       
    47     raise ValueError("No repositories found in $REPO_DIR")
       
    48 outputre = re.compile((r'! wall (\d+.\d+) comb \d+.\d+ user \d+.\d+ sys '
       
    49                        r'\d+.\d+ \(best of \d+\)'))
       
    50 
       
    51 def runperfcommand(reponame, command, *args, **kwargs):
       
    52     os.environ["HGRCPATH"] = os.environ.get("ASVHGRCPATH", "")
       
    53     ui = uimod.ui()
       
    54     repo = hg.repository(ui, os.path.join(reposdir, reponame))
       
    55     perfext = extensions.load(ui, 'perfext',
       
    56                               os.path.join(basedir, 'contrib', 'perf.py'))
       
    57     cmd = getattr(perfext, command)
       
    58     ui.pushbuffer()
       
    59     cmd(ui, repo, *args, **kwargs)
       
    60     output = ui.popbuffer()
       
    61     match = outputre.search(output)
       
    62     if not match:
       
    63         raise ValueError("Invalid output {0}".format(output))
       
    64     return float(match.group(1))
       
    65 
       
    66 def perfbench(repos=reposnames, name=None, params=None):
       
    67     """decorator to declare ASV benchmark based on contrib/perf.py extension
       
    68 
       
    69     An ASV benchmark is a python function with the given attributes:
       
    70 
       
    71     __name__: should start with track_, time_ or mem_ to be collected by ASV
       
    72     params and param_name: parameter matrix to display multiple graphs on the
       
    73     same page.
       
    74     pretty_name: If defined it's displayed in web-ui instead of __name__
       
    75     (useful for revsets)
       
    76     the module name is prepended to the benchmark name and displayed as
       
    77     "category" in webui.
       
    78 
       
    79     Benchmarks are automatically parameterized with repositories found in the
       
    80     REPOS_DIR environment variable.
       
    81 
       
    82     `params` is the param matrix in the form of a list of tuple
       
    83     (param_name, [value0, value1])
       
    84 
       
    85     For example [(x, [a, b]), (y, [c, d])] declare benchmarks for
       
    86     (a, c), (a, d), (b, c) and (b, d).
       
    87     """
       
    88     params = list(params or [])
       
    89     params.insert(0, ("repo", repos))
       
    90 
       
    91     def decorator(func):
       
    92         @functools.wraps(func)
       
    93         def wrapped(repo, *args):
       
    94             def perf(command, *a, **kw):
       
    95                 return runperfcommand(repo, command, *a, **kw)
       
    96             return func(perf, *args)
       
    97 
       
    98         wrapped.params = [p[1] for p in params]
       
    99         wrapped.param_names = [p[0] for p in params]
       
   100         wrapped.pretty_name = name
       
   101         return wrapped
       
   102     return decorator