Mercurial > public > mercurial-scm > hg
comparison mercurial/revset.py @ 25343:7fbef7932af9
revset: optimize 'or' operation of trivial revisions to a list
As seen in issue4565 and issue4624, GUI wrappers and automated scripts are
likely to generate a long query that just has numeric revisions joined by 'or'.
One reason why is that they allows users to choose arbitrary revisions from
a list. Because this use case isn't handled well by smartset, let's optimize
it to a plain old list.
Benchmarks:
1) reduce nesting of chained 'or' operations
2) optimize to a list (this patch)
revset #0: 0 + 1 + 2 + ... + 1000
1) wall 0.483341 comb 0.480000 user 0.480000 sys 0.000000 (best of 20)
2) wall 0.025393 comb 0.020000 user 0.020000 sys 0.000000 (best of 107)
revset #1: sort(0 + 1 + 2 + ... + 1000)
1) wall 0.035240 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
2) wall 0.026432 comb 0.030000 user 0.030000 sys 0.000000 (best of 102)
revset #2: first(0 + 1 + 2 + ... + 1000)
1) wall 0.028949 comb 0.030000 user 0.030000 sys 0.000000 (best of 100)
2) wall 0.025503 comb 0.030000 user 0.030000 sys 0.000000 (best of 106)
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 17 May 2015 15:11:38 +0900 |
parents | 5dde117269b6 |
children | ceaf04bb14ff |
comparison
equal
deleted
inserted
replaced
25342:5dde117269b6 | 25343:7fbef7932af9 |
---|---|
2167 | 2167 |
2168 if wa > wb: | 2168 if wa > wb: |
2169 return w, (op, tb, ta) | 2169 return w, (op, tb, ta) |
2170 return w, (op, ta, tb) | 2170 return w, (op, ta, tb) |
2171 elif op == 'or': | 2171 elif op == 'or': |
2172 ws, ts = zip(*[optimize(y, False) for y in x[1:]]) | 2172 # fast path for machine-generated expression, that is likely to have |
2173 # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()' | |
2174 ws, ts, ss = [], [], [] | |
2175 def flushss(): | |
2176 if not ss: | |
2177 return | |
2178 if len(ss) == 1: | |
2179 w, t = ss[0] | |
2180 else: | |
2181 s = '\0'.join(t[1] for w, t in ss) | |
2182 y = ('func', ('symbol', '_list'), ('string', s)) | |
2183 w, t = optimize(y, False) | |
2184 ws.append(w) | |
2185 ts.append(t) | |
2186 del ss[:] | |
2187 for y in x[1:]: | |
2188 w, t = optimize(y, False) | |
2189 if t[0] == 'string' or t[0] == 'symbol': | |
2190 ss.append((w, t)) | |
2191 continue | |
2192 flushss() | |
2193 ws.append(w) | |
2194 ts.append(t) | |
2195 flushss() | |
2196 if len(ts) == 1: | |
2197 return ws[0], ts[0] # 'or' operation is fully optimized out | |
2173 # we can't reorder trees by weight because it would change the order. | 2198 # we can't reorder trees by weight because it would change the order. |
2174 # ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a") | 2199 # ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a") |
2175 # ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0])) | 2200 # ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0])) |
2176 return max(ws), (op,) + ts | 2201 return max(ws), (op,) + tuple(ts) |
2177 elif op == 'not': | 2202 elif op == 'not': |
2178 # Optimize not public() to _notpublic() because we have a fast version | 2203 # Optimize not public() to _notpublic() because we have a fast version |
2179 if x[1] == ('func', ('symbol', 'public'), None): | 2204 if x[1] == ('func', ('symbol', 'public'), None): |
2180 newsym = ('func', ('symbol', '_notpublic'), None) | 2205 newsym = ('func', ('symbol', '_notpublic'), None) |
2181 o = optimize(newsym, not small) | 2206 o = optimize(newsym, not small) |