##// END OF EJS Templates
perf: add perfbranchmap command...
Pierre-Yves David -
r18304:9b6ae29d default
parent child Browse files
Show More
@@ -1,311 +1,366
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
5 from mercurial import repoview, branchmap
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 127 @command('perfmanifest')
128 128 def perfmanifest(ui, repo):
129 129 def d():
130 130 t = repo.manifest.tip()
131 131 m = repo.manifest.read(t)
132 132 repo.manifest.mapcache = None
133 133 repo.manifest._cache = None
134 134 timer(d)
135 135
136 136 @command('perfchangeset')
137 137 def perfchangeset(ui, repo, rev):
138 138 n = repo[rev].node()
139 139 def d():
140 140 c = repo.changelog.read(n)
141 141 #repo.changelog._cache = None
142 142 timer(d)
143 143
144 144 @command('perfindex')
145 145 def perfindex(ui, repo):
146 146 import mercurial.revlog
147 147 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
148 148 n = repo["tip"].node()
149 149 def d():
150 150 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
151 151 cl.rev(n)
152 152 timer(d)
153 153
154 154 @command('perfstartup')
155 155 def perfstartup(ui, repo):
156 156 cmd = sys.argv[0]
157 157 def d():
158 158 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
159 159 timer(d)
160 160
161 161 @command('perfparents')
162 162 def perfparents(ui, repo):
163 163 nl = [repo.changelog.node(i) for i in xrange(1000)]
164 164 def d():
165 165 for n in nl:
166 166 repo.changelog.parents(n)
167 167 timer(d)
168 168
169 169 @command('perflookup')
170 170 def perflookup(ui, repo, rev):
171 171 timer(lambda: len(repo.lookup(rev)))
172 172
173 173 @command('perfrevrange')
174 174 def perfrevrange(ui, repo, *specs):
175 175 revrange = scmutil.revrange
176 176 timer(lambda: len(revrange(repo, specs)))
177 177
178 178 @command('perfnodelookup')
179 179 def perfnodelookup(ui, repo, rev):
180 180 import mercurial.revlog
181 181 mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
182 182 n = repo[rev].node()
183 183 cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i")
184 184 def d():
185 185 cl.rev(n)
186 186 clearcaches(cl)
187 187 timer(d)
188 188
189 189 @command('perflog',
190 190 [('', 'rename', False, 'ask log to follow renames')])
191 191 def perflog(ui, repo, **opts):
192 192 ui.pushbuffer()
193 193 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
194 194 copies=opts.get('rename')))
195 195 ui.popbuffer()
196 196
197 197 @command('perftemplating')
198 198 def perftemplating(ui, repo):
199 199 ui.pushbuffer()
200 200 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
201 201 template='{date|shortdate} [{rev}:{node|short}]'
202 202 ' {author|person}: {desc|firstline}\n'))
203 203 ui.popbuffer()
204 204
205 205 @command('perfcca')
206 206 def perfcca(ui, repo):
207 207 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
208 208
209 209 @command('perffncacheload')
210 210 def perffncacheload(ui, repo):
211 211 s = repo.store
212 212 def d():
213 213 s.fncache._load()
214 214 timer(d)
215 215
216 216 @command('perffncachewrite')
217 217 def perffncachewrite(ui, repo):
218 218 s = repo.store
219 219 s.fncache._load()
220 220 def d():
221 221 s.fncache._dirty = True
222 222 s.fncache.write()
223 223 timer(d)
224 224
225 225 @command('perffncacheencode')
226 226 def perffncacheencode(ui, repo):
227 227 s = repo.store
228 228 s.fncache._load()
229 229 def d():
230 230 for p in s.fncache.entries:
231 231 s.encode(p)
232 232 timer(d)
233 233
234 234 @command('perfdiffwd')
235 235 def perfdiffwd(ui, repo):
236 236 """Profile diff of working directory changes"""
237 237 options = {
238 238 'w': 'ignore_all_space',
239 239 'b': 'ignore_space_change',
240 240 'B': 'ignore_blank_lines',
241 241 }
242 242
243 243 for diffopt in ('', 'w', 'b', 'B', 'wB'):
244 244 opts = dict((options[c], '1') for c in diffopt)
245 245 def d():
246 246 ui.pushbuffer()
247 247 commands.diff(ui, repo, **opts)
248 248 ui.popbuffer()
249 249 title = 'diffopts: %s' % (diffopt and ('-' + diffopt) or 'none')
250 250 timer(d, title)
251 251
252 252 @command('perfrevlog',
253 253 [('d', 'dist', 100, 'distance between the revisions')],
254 254 "[INDEXFILE]")
255 255 def perfrevlog(ui, repo, file_, **opts):
256 256 from mercurial import revlog
257 257 dist = opts['dist']
258 258 def d():
259 259 r = revlog.revlog(lambda fn: open(fn, 'rb'), file_)
260 260 for x in xrange(0, len(r), dist):
261 261 r.revision(r.node(x))
262 262
263 263 timer(d)
264 264
265 265 @command('perfrevset',
266 266 [('C', 'clear', False, 'clear volatile cache between each call.')],
267 267 "REVSET")
268 268 def perfrevset(ui, repo, expr, clear=False):
269 269 """benchmark the execution time of a revset
270 270
271 271 Use the --clean option if need to evaluate the impact of build volative
272 272 revisions set cache on the revset execution. Volatile cache hold filtered
273 273 and obsolete related cache."""
274 274 def d():
275 275 if clear:
276 276 repo.invalidatevolatilesets()
277 277 repo.revs(expr)
278 278 timer(d)
279 279
280 280 @command('perfvolatilesets')
281 281 def perfvolatilesets(ui, repo, *names):
282 282 """benchmark the computation of various volatile set
283 283
284 284 Volatile set computes element related to filtering and obsolescence."""
285 285 repo = repo.unfiltered()
286 286
287 287 def getobs(name):
288 288 def d():
289 289 repo.invalidatevolatilesets()
290 290 obsolete.getrevs(repo, name)
291 291 return d
292 292
293 293 allobs = sorted(obsolete.cachefuncs)
294 294 if names:
295 295 allobs = [n for n in allobs if n in names]
296 296
297 297 for name in allobs:
298 298 timer(getobs(name), title=name)
299 299
300 300 def getfiltered(name):
301 301 def d():
302 302 repo.invalidatevolatilesets()
303 303 repoview.filteredrevs(repo, name)
304 304 return d
305 305
306 306 allfilter = sorted(repoview.filtertable)
307 307 if names:
308 308 allfilter = [n for n in allfilter if n in names]
309 309
310 310 for name in allfilter:
311 311 timer(getfiltered(name), title=name)
312
313 @command('perfbranchmap',
314 [('f', 'full', False,
315 'Includes build time of subset'),
316 ])
317 def perfbranchmap(ui, repo, full=False):
318 """benchmark the update of a branchmap
319
320 This benchmarks the full repo.branchmap() call with read and write disabled
321 """
322 def getbranchmap(filtername):
323 """generate a benchmark function for the filtername"""
324 if filtername is None:
325 view = repo
326 else:
327 view = repo.filtered(filtername)
328 def d():
329 if full:
330 view._branchcaches.clear()
331 else:
332 view._branchcaches.pop(filtername, None)
333 view.branchmap()
334 return d
335 # add filter in smaller subset to bigger subset
336 possiblefilters = set(repoview.filtertable)
337 allfilters = []
338 while possiblefilters:
339 for name in possiblefilters:
340 subset = repoview.subsettable.get(name)
341 if subset not in possiblefilters:
342 break
343 else:
344 assert False, 'subset cycle %s!' % possiblefilters
345 allfilters.append(name)
346 possiblefilters.remove(name)
347
348 # warm the cache
349 if not full:
350 for name in allfilters:
351 repo.filtered(name).branchmap()
352 # add unfiltered
353 allfilters.append(None)
354 oldread = branchmap.read
355 oldwrite = branchmap.branchcache.write
356 try:
357 branchmap.read = lambda repo: None
358 branchmap.write = lambda repo: None
359 for name in allfilters:
360 timer(getbranchmap(name), title=str(name))
361 finally:
362 branchmap.read = oldread
363 branchmap.branchcache.write = oldwrite
364
365
366
General Comments 0
You need to be logged in to leave comments. Login now