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)