##// END OF EJS Templates
perf-helper: add a new sampling revset based on anti-chain...
marmoute -
r47501:36b4640c default
parent child Browse files
Show More
@@ -1,94 +1,139 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'scratch(REVS, <count>, [seed])')
21 @revsetpredicate(b'scratch(REVS, <count>, [seed])')
22 def scratch(repo, subset, x):
22 def scratch(repo, subset, x):
23 """randomly remove <count> revision from the repository top
23 """randomly remove <count> revision from the repository top
24
24
25 This subset is created by recursively picking changeset starting from the
25 This subset is created by recursively picking changeset starting from the
26 heads. It can be summarized using the following algorithm::
26 heads. It can be summarized using the following algorithm::
27
27
28 selected = set()
28 selected = set()
29 for i in range(<count>):
29 for i in range(<count>):
30 unselected = repo.revs("not <selected>")
30 unselected = repo.revs("not <selected>")
31 candidates = repo.revs("heads(<unselected>)")
31 candidates = repo.revs("heads(<unselected>)")
32 pick = random.choice(candidates)
32 pick = random.choice(candidates)
33 selected.add(pick)
33 selected.add(pick)
34 """
34 """
35 m = _(b"scratch expects revisions, count argument and an optional seed")
35 m = _(b"scratch expects revisions, count argument and an optional seed")
36 args = revsetlang.getargs(x, 2, 3, m)
36 args = revsetlang.getargs(x, 2, 3, m)
37 if len(args) == 2:
37 if len(args) == 2:
38 x, n = args
38 x, n = args
39 rand = random
39 rand = random
40 elif len(args) == 3:
40 elif len(args) == 3:
41 x, n, seed = args
41 x, n, seed = args
42 seed = revsetlang.getinteger(seed, _(b"seed should be a number"))
42 seed = revsetlang.getinteger(seed, _(b"seed should be a number"))
43 rand = random.Random(seed)
43 rand = random.Random(seed)
44 else:
44 else:
45 assert False
45 assert False
46
46
47 n = revsetlang.getinteger(n, _(b"scratch expects a number"))
47 n = revsetlang.getinteger(n, _(b"scratch expects a number"))
48
48
49 selected = set()
49 selected = set()
50 heads = set()
50 heads = set()
51 children_count = collections.defaultdict(lambda: 0)
51 children_count = collections.defaultdict(lambda: 0)
52 parents = repo.changelog._uncheckedparentrevs
52 parents = repo.changelog._uncheckedparentrevs
53
53
54 baseset = revset.getset(repo, smartset.fullreposet(repo), x)
54 baseset = revset.getset(repo, smartset.fullreposet(repo), x)
55 baseset.sort()
55 baseset.sort()
56 for r in baseset:
56 for r in baseset:
57 heads.add(r)
57 heads.add(r)
58
58
59 p1, p2 = parents(r)
59 p1, p2 = parents(r)
60 if p1 >= 0:
60 if p1 >= 0:
61 heads.discard(p1)
61 heads.discard(p1)
62 children_count[p1] += 1
62 children_count[p1] += 1
63 if p2 >= 0:
63 if p2 >= 0:
64 heads.discard(p2)
64 heads.discard(p2)
65 children_count[p2] += 1
65 children_count[p2] += 1
66
66
67 for h in heads:
67 for h in heads:
68 assert children_count[h] == 0
68 assert children_count[h] == 0
69
69
70 selected = set()
70 selected = set()
71 for x in range(n):
71 for x in range(n):
72 if not heads:
72 if not heads:
73 break
73 break
74 pick = rand.choice(list(heads))
74 pick = rand.choice(list(heads))
75 heads.remove(pick)
75 heads.remove(pick)
76 assert pick not in selected
76 assert pick not in selected
77 selected.add(pick)
77 selected.add(pick)
78 p1, p2 = parents(pick)
78 p1, p2 = parents(pick)
79 if p1 in children_count:
79 if p1 in children_count:
80 assert p1 in children_count
80 assert p1 in children_count
81 children_count[p1] -= 1
81 children_count[p1] -= 1
82 assert children_count[p1] >= 0
82 assert children_count[p1] >= 0
83 if children_count[p1] == 0:
83 if children_count[p1] == 0:
84 assert p1 not in selected, (r, p1)
84 assert p1 not in selected, (r, p1)
85 heads.add(p1)
85 heads.add(p1)
86 if p2 in children_count:
86 if p2 in children_count:
87 assert p2 in children_count
87 assert p2 in children_count
88 children_count[p2] -= 1
88 children_count[p2] -= 1
89 assert children_count[p2] >= 0
89 assert children_count[p2] >= 0
90 if children_count[p2] == 0:
90 if children_count[p2] == 0:
91 assert p2 not in selected, (r, p2)
91 assert p2 not in selected, (r, p2)
92 heads.add(p2)
92 heads.add(p2)
93
93
94 return smartset.baseset(selected) & subset
94 return smartset.baseset(selected) & subset
95
96
97 @revsetpredicate(b'randomantichain(REVS, [seed])')
98 def antichain(repo, subset, x):
99 """Pick a random anti-chain in the repository
100
101 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
103 word, all the elements are independant. It can be summarized with the
104 following algorithm::
105
106 selected = set()
107 unselected = repo.revs('all()')
108 while unselected:
109 pick = random.choice(unselected)
110 selected.add(pick)
111 unselected -= repo.revs('::<pick> + <pick>::')
112 """
113
114 args = revsetlang.getargs(
115 x, 1, 2, _(b"randomantichain expects revisions and an optional seed")
116 )
117 if len(args) == 1:
118 (x,) = args
119 rand = random
120 elif len(args) == 2:
121 x, seed = args
122 seed = revsetlang.getinteger(seed, _(b"seed should be a number"))
123 rand = random.Random(seed)
124 else:
125 assert False
126
127 selected = set()
128
129 baseset = revset.getset(repo, smartset.fullreposet(repo), x)
130 undecided = baseset
131
132 while undecided:
133 pick = rand.choice(list(undecided))
134 selected.add(pick)
135 undecided = repo.revs(
136 '%ld and not (::%ld or %ld::head())', baseset, selected, selected
137 )
138
139 return smartset.baseset(selected) & subset
General Comments 0
You need to be logged in to leave comments. Login now