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