##// END OF EJS Templates
perf-util: add an helper revset to use the same spec as the case search script...
marmoute -
r47506:63a3941d default
parent child Browse files
Show More
@@ -1,139 +1,170 b''
1 1 """revset to select sample of repository
2 2
3 3 Hopefully this is useful to create interesting discovery cases.
4 4 """
5 5
6 6 import collections
7 7 import random
8 8
9 9 from mercurial.i18n import _
10 10
11 11 from mercurial import (
12 12 registrar,
13 13 revset,
14 14 revsetlang,
15 15 smartset,
16 16 )
17 17
18 18 revsetpredicate = registrar.revsetpredicate()
19 19
20 20
21 @revsetpredicate(b'subsetspec("<spec>")')
22 def subsetmarkerspec(repo, subset, x):
23 """use a shorthand spec as used by search-discovery-case
24
25 Supported format are:
26
27 - "scratch-count-seed": not scratch(all(), count, "seed")
28 - "randomantichain-seed": ::randomantichain(all(), "seed")
29 - "rev-REV": "::REV"
30 """
31 args = revsetlang.getargs(
32 x, 0, 1, _(b'subsetspec("spec") required an argument')
33 )
34
35 spec = revsetlang.getstring(args[0], _(b"spec should be a string"))
36 case = spec.split(b'-')
37 t = case[0]
38 if t == b'scratch':
39 spec_revset = b'not scratch(all(), %s, "%s")' % (case[1], case[2])
40 elif t == b'randomantichain':
41 spec_revset = b'::randomantichain(all(), "%s")' % case[1]
42 elif t == b'rev':
43 spec_revset = b'::%d' % case[1]
44 else:
45 assert False, spec
46
47 selected = repo.revs(spec_revset)
48
49 return selected & subset
50
51
21 52 @revsetpredicate(b'scratch(REVS, <count>, [seed])')
22 53 def scratch(repo, subset, x):
23 54 """randomly remove <count> revision from the repository top
24 55
25 56 This subset is created by recursively picking changeset starting from the
26 57 heads. It can be summarized using the following algorithm::
27 58
28 59 selected = set()
29 60 for i in range(<count>):
30 61 unselected = repo.revs("not <selected>")
31 62 candidates = repo.revs("heads(<unselected>)")
32 63 pick = random.choice(candidates)
33 64 selected.add(pick)
34 65 """
35 66 m = _(b"scratch expects revisions, count argument and an optional seed")
36 67 args = revsetlang.getargs(x, 2, 3, m)
37 68 if len(args) == 2:
38 69 x, n = args
39 70 rand = random
40 71 elif len(args) == 3:
41 72 x, n, seed = args
42 73 seed = revsetlang.getinteger(seed, _(b"seed should be a number"))
43 74 rand = random.Random(seed)
44 75 else:
45 76 assert False
46 77
47 78 n = revsetlang.getinteger(n, _(b"scratch expects a number"))
48 79
49 80 selected = set()
50 81 heads = set()
51 82 children_count = collections.defaultdict(lambda: 0)
52 83 parents = repo.changelog._uncheckedparentrevs
53 84
54 85 baseset = revset.getset(repo, smartset.fullreposet(repo), x)
55 86 baseset.sort()
56 87 for r in baseset:
57 88 heads.add(r)
58 89
59 90 p1, p2 = parents(r)
60 91 if p1 >= 0:
61 92 heads.discard(p1)
62 93 children_count[p1] += 1
63 94 if p2 >= 0:
64 95 heads.discard(p2)
65 96 children_count[p2] += 1
66 97
67 98 for h in heads:
68 99 assert children_count[h] == 0
69 100
70 101 selected = set()
71 102 for x in range(n):
72 103 if not heads:
73 104 break
74 105 pick = rand.choice(list(heads))
75 106 heads.remove(pick)
76 107 assert pick not in selected
77 108 selected.add(pick)
78 109 p1, p2 = parents(pick)
79 110 if p1 in children_count:
80 111 assert p1 in children_count
81 112 children_count[p1] -= 1
82 113 assert children_count[p1] >= 0
83 114 if children_count[p1] == 0:
84 115 assert p1 not in selected, (r, p1)
85 116 heads.add(p1)
86 117 if p2 in children_count:
87 118 assert p2 in children_count
88 119 children_count[p2] -= 1
89 120 assert children_count[p2] >= 0
90 121 if children_count[p2] == 0:
91 122 assert p2 not in selected, (r, p2)
92 123 heads.add(p2)
93 124
94 125 return smartset.baseset(selected) & subset
95 126
96 127
97 128 @revsetpredicate(b'randomantichain(REVS, [seed])')
98 129 def antichain(repo, subset, x):
99 130 """Pick a random anti-chain in the repository
100 131
101 132 A antichain is a set of changeset where there isn't any element that is
102 133 either a descendant or ancestors of any other element in the set. In other
103 134 word, all the elements are independant. It can be summarized with the
104 135 following algorithm::
105 136
106 137 selected = set()
107 138 unselected = repo.revs('all()')
108 139 while unselected:
109 140 pick = random.choice(unselected)
110 141 selected.add(pick)
111 142 unselected -= repo.revs('::<pick> + <pick>::')
112 143 """
113 144
114 145 args = revsetlang.getargs(
115 146 x, 1, 2, _(b"randomantichain expects revisions and an optional seed")
116 147 )
117 148 if len(args) == 1:
118 149 (x,) = args
119 150 rand = random
120 151 elif len(args) == 2:
121 152 x, seed = args
122 153 seed = revsetlang.getinteger(seed, _(b"seed should be a number"))
123 154 rand = random.Random(seed)
124 155 else:
125 156 assert False
126 157
127 158 selected = set()
128 159
129 160 baseset = revset.getset(repo, smartset.fullreposet(repo), x)
130 161 undecided = baseset
131 162
132 163 while undecided:
133 164 pick = rand.choice(list(undecided))
134 165 selected.add(pick)
135 166 undecided = repo.revs(
136 167 '%ld and not (::%ld or %ld::head())', baseset, selected, selected
137 168 )
138 169
139 170 return smartset.baseset(selected) & subset
General Comments 0
You need to be logged in to leave comments. Login now