#!/usr/bin/env python3 # compare various algorithm variants for a given case # # search-discovery-case REPO LOCAL_CASE REMOTE_CASE # # The description for the case input uses the same format as the ouput of # search-discovery-case import json import os import subprocess import sys this_script = os.path.abspath(sys.argv[0]) script_name = os.path.basename(this_script) this_dir = os.path.dirname(this_script) hg_dir = os.path.join(this_dir, '..', '..') HG_REPO = os.path.normpath(hg_dir) HG_BIN = os.path.join(HG_REPO, 'hg') SUBSET_PATH = os.path.join(HG_REPO, 'contrib', 'perf-utils', 'subsetmaker.py') CMD_BASE = ( HG_BIN, 'debugdiscovery', '--template', 'json', '--config', 'extensions.subset=%s' % SUBSET_PATH, ) # --old # --nonheads # # devel.discovery.exchange-heads=True # devel.discovery.grow-sample=True # devel.discovery.grow-sample.dynamic=True VARIANTS = { 'tree-discovery': ('--old',), 'set-discovery-basic': ( '--config', 'devel.discovery.exchange-heads=no', '--config', 'devel.discovery.grow-sample=no', '--config', 'devel.discovery.grow-sample.dynamic=no', '--config', 'devel.discovery.randomize=yes', ), 'set-discovery-heads': ( '--config', 'devel.discovery.exchange-heads=yes', '--config', 'devel.discovery.grow-sample=no', '--config', 'devel.discovery.grow-sample.dynamic=no', '--config', 'devel.discovery.randomize=yes', ), 'set-discovery-grow-sample': ( '--config', 'devel.discovery.exchange-heads=yes', '--config', 'devel.discovery.grow-sample=yes', '--config', 'devel.discovery.grow-sample.dynamic=no', '--config', 'devel.discovery.randomize=yes', ), 'set-discovery-dynamic-sample': ( '--config', 'devel.discovery.exchange-heads=yes', '--config', 'devel.discovery.grow-sample=yes', '--config', 'devel.discovery.grow-sample.dynamic=yes', '--config', 'devel.discovery.randomize=yes', ), 'set-discovery-default': ( '--config', 'devel.discovery.randomize=yes', ), } VARIANTS_KEYS = [ 'tree-discovery', 'set-discovery-basic', 'set-discovery-heads', 'set-discovery-grow-sample', 'set-discovery-dynamic-sample', 'set-discovery-default', ] assert set(VARIANTS.keys()) == set(VARIANTS_KEYS) def parse_case(case): case_type, case_args = case.split('-', 1) if case_type == 'file': case_args = (case_args,) else: case_args = tuple(int(x) for x in case_args.split('-')) case = (case_type,) + case_args return case def format_case(case): return '-'.join(str(s) for s in case) def to_revsets(case): t = case[0] if t == 'scratch': return 'not scratch(all(), %d, "%d")' % (case[1], case[2]) elif t == 'randomantichain': return '::randomantichain(all(), "%d")' % case[1] elif t == 'rev': return '::%d' % case[1] elif t == 'file': return '::nodefromfile("%s")' % case[1] else: assert False def compare( repo, local_case, remote_case, display_header=True, display_case=True, ): case = (repo, local_case, remote_case) if display_header: pieces = ['#'] if display_case: pieces += [ "repo", "local-subset", "remote-subset", ] pieces += [ "discovery-variant", "roundtrips", "queries", "revs", "local-heads", "common-heads", "undecided-initial", "undecided-common", "undecided-missing", ] print(*pieces) for variant in VARIANTS_KEYS: res = process(case, VARIANTS[variant]) revs = res["nb-revs"] local_heads = res["nb-head-local"] common_heads = res["nb-common-heads"] roundtrips = res["total-roundtrips"] queries = res["total-queries"] pieces = [] if display_case: pieces += [ repo, format_case(local_case), format_case(remote_case), ] pieces += [ variant, roundtrips, queries, revs, local_heads, common_heads, ] if 'tree-discovery' not in variant: undecided_common = res["nb-ini_und-common"] undecided_missing = res["nb-ini_und-missing"] undecided = undecided_common + undecided_missing pieces += [ undecided, undecided_common, undecided_missing, ] print(*pieces) return 0 def process(case, variant): (repo, left, right) = case cmd = list(CMD_BASE) cmd.append('-R') cmd.append(repo) cmd.append('--local-as-revs') cmd.append(to_revsets(left)) cmd.append('--remote-as-revs') cmd.append(to_revsets(right)) cmd.extend(variant) s = subprocess.Popen(cmd, stdout=subprocess.PIPE) out, err = s.communicate() return json.loads(out)[0] if __name__ == '__main__': argv = sys.argv[:] kwargs = {} # primitive arg parsing if '--no-header' in argv: kwargs['display_header'] = False argv = [a for a in argv if a != '--no-header'] if '--no-case' in argv: kwargs['display_case'] = False argv = [a for a in argv if a != '--no-case'] if len(argv) != 4: usage = f'USAGE: {script_name} REPO LOCAL_CASE REMOTE_CASE' print(usage, file=sys.stderr) sys.exit(128) repo = argv[1] local_case = parse_case(argv[2]) remote_case = parse_case(argv[3]) sys.exit(compare(repo, local_case, remote_case, **kwargs))