##// END OF EJS Templates
perf: add a command to measure merge.calculateupdates perf...
Siddharth Agarwal -
r18817:c760acc6 default
parent child Browse files
Show More
@@ -1,366 +1,382 b''
1 1 # perf.py - performance test routines
2 2 '''helper extension to measure performance'''
3 3
4 4 from mercurial import cmdutil, scmutil, util, match, commands, obsolete
5 from mercurial import repoview, branchmap
5 from mercurial import repoview, branchmap, merge
6 6 import time, os, sys
7 7
8 8 cmdtable = {}
9 9 command = cmdutil.command(cmdtable)
10 10
11 11 def timer(func, title=None):
12 12 results = []
13 13 begin = time.time()
14 14 count = 0
15 15 while True:
16 16 ostart = os.times()
17 17 cstart = time.time()
18 18 r = func()
19 19 cstop = time.time()
20 20 ostop = os.times()
21 21 count += 1
22 22 a, b = ostart, ostop
23 23 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
24 24 if cstop - begin > 3 and count >= 100:
25 25 break
26 26 if cstop - begin > 10 and count >= 3:
27 27 break
28 28 if title:
29 29 sys.stderr.write("! %s\n" % title)
30 30 if r:
31 31 sys.stderr.write("! result: %s\n" % r)
32 32 m = min(results)
33 33 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
34 34 % (m[0], m[1] + m[2], m[1], m[2], count))
35 35
36 36 @command('perfwalk')
37 37 def perfwalk(ui, repo, *pats):
38 38 try:
39 39 m = scmutil.match(repo[None], pats, {})
40 40 timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
41 41 except Exception:
42 42 try:
43 43 m = scmutil.match(repo[None], pats, {})
44 44 timer(lambda: len([b for a, b, c in repo.dirstate.statwalk([], m)]))
45 45 except Exception:
46 46 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
47 47
48 48 @command('perfstatus',
49 49 [('u', 'unknown', False,
50 50 'ask status to look for unknown files')])
51 51 def perfstatus(ui, repo, **opts):
52 52 #m = match.always(repo.root, repo.getcwd())
53 53 #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
54 54 # False))))
55 55 timer(lambda: sum(map(len, repo.status(**opts))))
56 56
57 57 def clearcaches(cl):
58 58 # behave somewhat consistently across internal API changes
59 59 if util.safehasattr(cl, 'clearcaches'):
60 60 cl.clearcaches()
61 61 elif util.safehasattr(cl, '_nodecache'):
62 62 from mercurial.node import nullid, nullrev
63 63 cl._nodecache = {nullid: nullrev}
64 64 cl._nodepos = None
65 65
66 66 @command('perfheads')
67 67 def perfheads(ui, repo):
68 68 cl = repo.changelog
69 69 def d():
70 70 len(cl.headrevs())
71 71 clearcaches(cl)
72 72 timer(d)
73 73
74 74 @command('perftags')
75 75 def perftags(ui, repo):
76 76 import mercurial.changelog, mercurial.manifest
77 77 def t():
78 78 repo.changelog = mercurial.changelog.changelog(repo.sopener)
79 79 repo.manifest = mercurial.manifest.manifest(repo.sopener)
80 80 repo._tags = None
81 81 return len(repo.tags())
82 82 timer(t)
83 83
84 84 @command('perfancestors')
85 85 def perfancestors(ui, repo):
86 86 heads = repo.changelog.headrevs()
87 87 def d():
88 88 for a in repo.changelog.ancestors(heads):
89 89 pass
90 90 timer(d)
91 91
92 92 @command('perfancestorset')
93 93 def perfancestorset(ui, repo, revset):
94 94 revs = repo.revs(revset)
95 95 heads = repo.changelog.headrevs()
96 96 def d():
97 97 s = repo.changelog.ancestors(heads)
98 98 for rev in revs:
99 99 rev in s
100 100 timer(d)
101 101
102 102 @command('perfdirstate')
103 103 def perfdirstate(ui, repo):
104 104 "a" in repo.dirstate
105 105 def d():
106 106 repo.dirstate.invalidate()
107 107 "a" in repo.dirstate
108 108 timer(d)
109 109
110 110 @command('perfdirstatedirs')
111 111 def perfdirstatedirs(ui, repo):
112 112 "a" in repo.dirstate
113 113 def d():
114 114 "a" in repo.dirstate._dirs
115 115 del repo.dirstate._dirs
116 116 timer(d)
117 117
118 118 @command('perfdirstatewrite')
119 119 def perfdirstatewrite(ui, repo):
120 120 ds = repo.dirstate
121 121 "a" in ds
122 122 def d():
123 123 ds._dirty = True
124 124 ds.write()
125 125 timer(d)
126 126
127 @command('perfmergecalculate',
128 [('r', 'rev', '.', 'rev to merge against')])
129 def perfmergecalculate(ui, repo, rev):
130 wctx = repo[None]
131 rctx = scmutil.revsingle(repo, rev, rev)
132 ancestor = wctx.ancestor(rctx)
133 # we don't want working dir files to be stat'd in the benchmark, so prime
134 # that cache
135 wctx.dirty()
136 def d():
137 # acceptremote is True because we don't want prompts in the middle of
138 # our benchmark
139 merge.calculateupdates(repo, wctx, rctx, ancestor, False, False, False,
140 acceptremote=True)
141 timer(d)
142
127 143 @command('perfmanifest')
128 144 def perfmanifest(ui, repo):
129 145 def d():
130 146 t = repo.manifest.tip()
131 147 m = repo.manifest.read(t)
132 148 repo.manifest.mapcache = None
133 149 repo.manifest._cache = None
134 150 timer(d)
135 151
136 152 @command('perfchangeset')
137 153 def perfchangeset(ui, repo, rev):
138 154 n = repo[rev].node()
139 155 def d():
140 156 c = repo.changelog.read(n)
141 157 #repo.changelog._cache = None
142 158 timer(d)
143 159
144 160 @command('perfindex')
145 161 def perfindex(ui, repo):
146 162 import mercurial.revlog
147 163 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
148 164 n = repo["tip"].node()
149 165 def d():
150 166 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
151 167 cl.rev(n)
152 168 timer(d)
153 169
154 170 @command('perfstartup')
155 171 def perfstartup(ui, repo):
156 172 cmd = sys.argv[0]
157 173 def d():
158 174 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
159 175 timer(d)
160 176
161 177 @command('perfparents')
162 178 def perfparents(ui, repo):
163 179 nl = [repo.changelog.node(i) for i in xrange(1000)]
164 180 def d():
165 181 for n in nl:
166 182 repo.changelog.parents(n)
167 183 timer(d)
168 184
169 185 @command('perflookup')
170 186 def perflookup(ui, repo, rev):
171 187 timer(lambda: len(repo.lookup(rev)))
172 188
173 189 @command('perfrevrange')
174 190 def perfrevrange(ui, repo, *specs):
175 191 revrange = scmutil.revrange
176 192 timer(lambda: len(revrange(repo, specs)))
177 193
178 194 @command('perfnodelookup')
179 195 def perfnodelookup(ui, repo, rev):
180 196 import mercurial.revlog
181 197 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
182 198 n = repo[rev].node()
183 199 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
184 200 def d():
185 201 cl.rev(n)
186 202 clearcaches(cl)
187 203 timer(d)
188 204
189 205 @command('perflog',
190 206 [('', 'rename', False, 'ask log to follow renames')])
191 207 def perflog(ui, repo, **opts):
192 208 ui.pushbuffer()
193 209 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
194 210 copies=opts.get('rename')))
195 211 ui.popbuffer()
196 212
197 213 @command('perftemplating')
198 214 def perftemplating(ui, repo):
199 215 ui.pushbuffer()
200 216 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
201 217 template='{date|shortdate} [{rev}:{node|short}]'
202 218 ' {author|person}: {desc|firstline}\n'))
203 219 ui.popbuffer()
204 220
205 221 @command('perfcca')
206 222 def perfcca(ui, repo):
207 223 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
208 224
209 225 @command('perffncacheload')
210 226 def perffncacheload(ui, repo):
211 227 s = repo.store
212 228 def d():
213 229 s.fncache._load()
214 230 timer(d)
215 231
216 232 @command('perffncachewrite')
217 233 def perffncachewrite(ui, repo):
218 234 s = repo.store
219 235 s.fncache._load()
220 236 def d():
221 237 s.fncache._dirty = True
222 238 s.fncache.write()
223 239 timer(d)
224 240
225 241 @command('perffncacheencode')
226 242 def perffncacheencode(ui, repo):
227 243 s = repo.store
228 244 s.fncache._load()
229 245 def d():
230 246 for p in s.fncache.entries:
231 247 s.encode(p)
232 248 timer(d)
233 249
234 250 @command('perfdiffwd')
235 251 def perfdiffwd(ui, repo):
236 252 """Profile diff of working directory changes"""
237 253 options = {
238 254 'w': 'ignore_all_space',
239 255 'b': 'ignore_space_change',
240 256 'B': 'ignore_blank_lines',
241 257 }
242 258
243 259 for diffopt in ('', 'w', 'b', 'B', 'wB'):
244 260 opts = dict((options[c], '1') for c in diffopt)
245 261 def d():
246 262 ui.pushbuffer()
247 263 commands.diff(ui, repo, **opts)
248 264 ui.popbuffer()
249 265 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
250 266 timer(d, title)
251 267
252 268 @command('perfrevlog',
253 269 [('d', 'dist', 100, 'distance between the revisions')],
254 270 "[INDEXFILE]")
255 271 def perfrevlog(ui, repo, file_, **opts):
256 272 from mercurial import revlog
257 273 dist = opts['dist']
258 274 def d():
259 275 r = revlog.revlog(lambda fn: open(fn, 'rb'), file_)
260 276 for x in xrange(0, len(r), dist):
261 277 r.revision(r.node(x))
262 278
263 279 timer(d)
264 280
265 281 @command('perfrevset',
266 282 [('C', 'clear', False, 'clear volatile cache between each call.')],
267 283 "REVSET")
268 284 def perfrevset(ui, repo, expr, clear=False):
269 285 """benchmark the execution time of a revset
270 286
271 287 Use the --clean option if need to evaluate the impact of build volatile
272 288 revisions set cache on the revset execution. Volatile cache hold filtered
273 289 and obsolete related cache."""
274 290 def d():
275 291 if clear:
276 292 repo.invalidatevolatilesets()
277 293 repo.revs(expr)
278 294 timer(d)
279 295
280 296 @command('perfvolatilesets')
281 297 def perfvolatilesets(ui, repo, *names):
282 298 """benchmark the computation of various volatile set
283 299
284 300 Volatile set computes element related to filtering and obsolescence."""
285 301 repo = repo.unfiltered()
286 302
287 303 def getobs(name):
288 304 def d():
289 305 repo.invalidatevolatilesets()
290 306 obsolete.getrevs(repo, name)
291 307 return d
292 308
293 309 allobs = sorted(obsolete.cachefuncs)
294 310 if names:
295 311 allobs = [n for n in allobs if n in names]
296 312
297 313 for name in allobs:
298 314 timer(getobs(name), title=name)
299 315
300 316 def getfiltered(name):
301 317 def d():
302 318 repo.invalidatevolatilesets()
303 319 repoview.filteredrevs(repo, name)
304 320 return d
305 321
306 322 allfilter = sorted(repoview.filtertable)
307 323 if names:
308 324 allfilter = [n for n in allfilter if n in names]
309 325
310 326 for name in allfilter:
311 327 timer(getfiltered(name), title=name)
312 328
313 329 @command('perfbranchmap',
314 330 [('f', 'full', False,
315 331 'Includes build time of subset'),
316 332 ])
317 333 def perfbranchmap(ui, repo, full=False):
318 334 """benchmark the update of a branchmap
319 335
320 336 This benchmarks the full repo.branchmap() call with read and write disabled
321 337 """
322 338 def getbranchmap(filtername):
323 339 """generate a benchmark function for the filtername"""
324 340 if filtername is None:
325 341 view = repo
326 342 else:
327 343 view = repo.filtered(filtername)
328 344 def d():
329 345 if full:
330 346 view._branchcaches.clear()
331 347 else:
332 348 view._branchcaches.pop(filtername, None)
333 349 view.branchmap()
334 350 return d
335 351 # add filter in smaller subset to bigger subset
336 352 possiblefilters = set(repoview.filtertable)
337 353 allfilters = []
338 354 while possiblefilters:
339 355 for name in possiblefilters:
340 356 subset = repoview.subsettable.get(name)
341 357 if subset not in possiblefilters:
342 358 break
343 359 else:
344 360 assert False, 'subset cycle %s!' % possiblefilters
345 361 allfilters.append(name)
346 362 possiblefilters.remove(name)
347 363
348 364 # warm the cache
349 365 if not full:
350 366 for name in allfilters:
351 367 repo.filtered(name).branchmap()
352 368 # add unfiltered
353 369 allfilters.append(None)
354 370 oldread = branchmap.read
355 371 oldwrite = branchmap.branchcache.write
356 372 try:
357 373 branchmap.read = lambda repo: None
358 374 branchmap.write = lambda repo: None
359 375 for name in allfilters:
360 376 timer(getbranchmap(name), title=str(name))
361 377 finally:
362 378 branchmap.read = oldread
363 379 branchmap.branchcache.write = oldwrite
364 380
365 381
366 382
General Comments 0
You need to be logged in to leave comments. Login now