diff -r 57875cf423c9 -r 2372284d9457 contrib/revsetbenchmarks.py --- a/contrib/revsetbenchmarks.py Sat Oct 05 10:29:34 2019 -0400 +++ b/contrib/revsetbenchmarks.py Sun Oct 06 09:45:02 2019 -0400 @@ -16,9 +16,20 @@ import subprocess import sys -DEFAULTVARIANTS = ['plain', 'min', 'max', 'first', 'last', - 'reverse', 'reverse+first', 'reverse+last', - 'sort', 'sort+first', 'sort+last'] +DEFAULTVARIANTS = [ + 'plain', + 'min', + 'max', + 'first', + 'last', + 'reverse', + 'reverse+first', + 'reverse+last', + 'sort', + 'sort+first', + 'sort+last', +] + def check_output(*args, **kwargs): kwargs.setdefault('stderr', subprocess.PIPE) @@ -29,14 +40,16 @@ raise subprocess.CalledProcessError(proc.returncode, ' '.join(args[0])) return output + def update(rev): """update the repo to a revision""" try: subprocess.check_call(['hg', 'update', '--quiet', '--check', str(rev)]) - check_output(['make', 'local'], - stderr=None) # suppress output except for error/warning + check_output( + ['make', 'local'], stderr=None + ) # suppress output except for error/warning except subprocess.CalledProcessError as exc: - print('update to revision %s failed, aborting'%rev, file=sys.stderr) + print('update to revision %s failed, aborting' % rev, file=sys.stderr) sys.exit(exc.returncode) @@ -48,11 +61,14 @@ fullcmd = ['./hg'] if repo is not None: fullcmd += ['-R', repo] - fullcmd += ['--config', - 'extensions.perf=' + os.path.join(contribdir, 'perf.py')] + fullcmd += [ + '--config', + 'extensions.perf=' + os.path.join(contribdir, 'perf.py'), + ] fullcmd += cmd return check_output(fullcmd, stderr=subprocess.STDOUT) + def perf(revset, target=None, contexts=False): """run benchmark for this very revset""" try: @@ -64,15 +80,21 @@ output = hg(args, repo=target) return parseoutput(output) except subprocess.CalledProcessError as exc: - print('abort: cannot run revset benchmark: %s'%exc.cmd, file=sys.stderr) - if getattr(exc, 'output', None) is None: # no output before 2.7 + print( + 'abort: cannot run revset benchmark: %s' % exc.cmd, file=sys.stderr + ) + if getattr(exc, 'output', None) is None: # no output before 2.7 print('(no output)', file=sys.stderr) else: print(exc.output, file=sys.stderr) return None -outputre = re.compile(br'! wall (\d+.\d+) comb (\d+.\d+) user (\d+.\d+) ' - br'sys (\d+.\d+) \(best of (\d+)\)') + +outputre = re.compile( + br'! wall (\d+.\d+) comb (\d+.\d+) user (\d+.\d+) ' + br'sys (\d+.\d+) \(best of (\d+)\)' +) + def parseoutput(output): """parse a textual output into a dict @@ -85,20 +107,30 @@ print('abort: invalid output:', file=sys.stderr) print(output, file=sys.stderr) sys.exit(1) - return {'comb': float(match.group(2)), - 'count': int(match.group(5)), - 'sys': float(match.group(3)), - 'user': float(match.group(4)), - 'wall': float(match.group(1)), - } + return { + 'comb': float(match.group(2)), + 'count': int(match.group(5)), + 'sys': float(match.group(3)), + 'user': float(match.group(4)), + 'wall': float(match.group(1)), + } + def printrevision(rev): """print data about a revision""" sys.stdout.write("Revision ") sys.stdout.flush() - subprocess.check_call(['hg', 'log', '--rev', str(rev), '--template', - '{if(tags, " ({tags})")} ' - '{rev}:{node|short}: {desc|firstline}\n']) + subprocess.check_call( + [ + 'hg', + 'log', + '--rev', + str(rev), + '--template', + '{if(tags, " ({tags})")} ' '{rev}:{node|short}: {desc|firstline}\n', + ] + ) + def idxwidth(nbidx): """return the max width of number used for index @@ -107,7 +139,7 @@ because we start with zero and we'd rather not deal with all the extra rounding business that log10 would imply. """ - nbidx -= 1 # starts at 0 + nbidx -= 1 # starts at 0 idxwidth = 0 while nbidx: idxwidth += 1 @@ -116,6 +148,7 @@ idxwidth = 1 return idxwidth + def getfactor(main, other, field, sensitivity=0.05): """return the relative factor between values for 'field' in main and other @@ -125,10 +158,11 @@ if main is not None: factor = other[field] / main[field] low, high = 1 - sensitivity, 1 + sensitivity - if (low < factor < high): + if low < factor < high: return None return factor + def formatfactor(factor): """format a factor into a 4 char string @@ -155,15 +189,19 @@ factor //= 0 return 'x%ix%i' % (factor, order) + def formattiming(value): """format a value to strictly 8 char, dropping some precision if needed""" - if value < 10**7: + if value < 10 ** 7: return ('%.6f' % value)[:8] else: # value is HUGE very unlikely to happen (4+ month run) return '%i' % value + _marker = object() + + def printresult(variants, idx, data, maxidx, verbose=False, reference=_marker): """print a line of result to stdout""" mask = '%%0%ii) %%s' % idxwidth(maxidx) @@ -184,9 +222,10 @@ out.append(formattiming(data[var]['comb'])) out.append(formattiming(data[var]['user'])) out.append(formattiming(data[var]['sys'])) - out.append('%6d' % data[var]['count']) + out.append('%6d' % data[var]['count']) print(mask % (idx, ' '.join(out))) + def printheader(variants, maxidx, verbose=False, relative=False): header = [' ' * (idxwidth(maxidx) + 1)] for var in variants: @@ -204,12 +243,13 @@ header.append('%6s' % 'count') print(' '.join(header)) + def getrevs(spec): """get the list of rev matched by a revset""" try: out = check_output(['hg', 'log', '--template={rev}\n', '--rev', spec]) except subprocess.CalledProcessError as exc: - print("abort, can't get revision from %s"%spec, file=sys.stderr) + print("abort, can't get revision from %s" % spec, file=sys.stderr) sys.exit(exc.returncode) return [r for r in out.split() if r] @@ -221,31 +261,44 @@ revset = '%s(%s)' % (var, revset) return revset -helptext="""This script will run multiple variants of provided revsets using + +helptext = """This script will run multiple variants of provided revsets using different revisions in your mercurial repository. After the benchmark are run summary output is provided. Use it to demonstrate speed improvements or pin point regressions. Revsets to run are specified in a file (or from stdin), one revsets per line. Line starting with '#' will be ignored, allowing insertion of comments.""" -parser = optparse.OptionParser(usage="usage: %prog [options] ", - description=helptext) -parser.add_option("-f", "--file", - help="read revset from FILE (stdin if omitted)", - metavar="FILE") -parser.add_option("-R", "--repo", - help="run benchmark on REPO", metavar="REPO") +parser = optparse.OptionParser( + usage="usage: %prog [options] ", description=helptext +) +parser.add_option( + "-f", + "--file", + help="read revset from FILE (stdin if omitted)", + metavar="FILE", +) +parser.add_option("-R", "--repo", help="run benchmark on REPO", metavar="REPO") -parser.add_option("-v", "--verbose", - action='store_true', - help="display all timing data (not just best total time)") +parser.add_option( + "-v", + "--verbose", + action='store_true', + help="display all timing data (not just best total time)", +) -parser.add_option("", "--variants", - default=','.join(DEFAULTVARIANTS), - help="comma separated list of variant to test " - "(eg: plain,min,sorted) (plain = no modification)") -parser.add_option('', '--contexts', - action='store_true', - help='obtain changectx from results instead of integer revs') +parser.add_option( + "", + "--variants", + default=','.join(DEFAULTVARIANTS), + help="comma separated list of variant to test " + "(eg: plain,min,sorted) (plain = no modification)", +) +parser.add_option( + '', + '--contexts', + action='store_true', + help='obtain changectx from results instead of integer revs', +) (options, args) = parser.parse_args() @@ -294,17 +347,20 @@ data = perf(varrset, target=options.repo, contexts=options.contexts) varres[var] = data res.append(varres) - printresult(variants, idx, varres, len(revsets), - verbose=options.verbose) + printresult( + variants, idx, varres, len(revsets), verbose=options.verbose + ) sys.stdout.flush() print("----------------------------") -print(""" +print( + """ Result by revset ================ -""") +""" +) print('Revision:') for idx, rev in enumerate(revs): @@ -321,7 +377,13 @@ printheader(variants, len(results), verbose=options.verbose, relative=True) ref = None for idx, data in enumerate(results): - printresult(variants, idx, data[ridx], len(results), - verbose=options.verbose, reference=ref) + printresult( + variants, + idx, + data[ridx], + len(results), + verbose=options.verbose, + reference=ref, + ) ref = data[ridx] print()