comparison mercurial/linelog.py @ 39009:ee97f7a677f3

linelog: optimize replacelines The optimization to avoid calling `annotate` inside `replacelines` is significant for practical use patterns. Before this patch: hg perflinelogedits ! wall 6.778478 comb 6.710000 user 6.700000 sys 0.010000 (best of 3) After this patch: hg perflinelogedits ! wall 0.136573 comb 0.140000 user 0.130000 sys 0.010000 (best of 63) Differential Revision: https://phab.mercurial-scm.org/D4150
author Jun Wu <quark@fb.com>
date Tue, 07 Aug 2018 17:22:33 -0700
parents 32b1967b8734
children 2372284d9457
comparison
equal deleted inserted replaced
39008:32b1967b8734 39009:ee97f7a677f3
311 programlen = self._program.__len__ 311 programlen = self._program.__len__
312 oldproglen = programlen() 312 oldproglen = programlen()
313 appendinst = self._program.append 313 appendinst = self._program.append
314 314
315 # insert 315 # insert
316 blineinfos = []
317 bappend = blineinfos.append
316 if b1 < b2: 318 if b1 < b2:
317 # Determine the jump target for the JGE at the start of 319 # Determine the jump target for the JGE at the start of
318 # the new block. 320 # the new block.
319 tgt = oldproglen + (b2 - b1 + 1) 321 tgt = oldproglen + (b2 - b1 + 1)
320 # Jump to skip the insert if we're at an older revision. 322 # Jump to skip the insert if we're at an older revision.
321 appendinst(_jl(rev, tgt)) 323 appendinst(_jl(rev, tgt))
322 for linenum in pycompat.xrange(b1, b2): 324 for linenum in pycompat.xrange(b1, b2):
323 if _internal_blines is None: 325 if _internal_blines is None:
326 bappend(lineinfo(rev, linenum, programlen()))
324 appendinst(_line(rev, linenum)) 327 appendinst(_line(rev, linenum))
325 else: 328 else:
326 appendinst(_line(*_internal_blines[linenum])) 329 newrev, newlinenum = _internal_blines[linenum]
330 bappend(lineinfo(newrev, newlinenum, programlen()))
331 appendinst(_line(newrev, newlinenum))
327 # delete 332 # delete
328 if a1 < a2: 333 if a1 < a2:
329 if a2 > len(ar.lines): 334 if a2 > len(ar.lines):
330 raise LineLogError( 335 raise LineLogError(
331 '%d contains %d lines, tried to access line %d' % ( 336 '%d contains %d lines, tried to access line %d' % (
340 # invisible lines between a2-1 and a2 (IOW, lines that 345 # invisible lines between a2-1 and a2 (IOW, lines that
341 # are added later). 346 # are added later).
342 endaddr = ar.lines[a2 - 1]._offset + 1 347 endaddr = ar.lines[a2 - 1]._offset + 1
343 appendinst(_jge(rev, endaddr)) 348 appendinst(_jge(rev, endaddr))
344 # copy instruction from a1 349 # copy instruction from a1
350 a1instpc = programlen()
345 appendinst(a1inst) 351 appendinst(a1inst)
346 # if a1inst isn't a jump or EOF, then we need to add an unconditional 352 # if a1inst isn't a jump or EOF, then we need to add an unconditional
347 # jump back into the program here. 353 # jump back into the program here.
348 if not isinstance(a1inst, (_jump, _eof)): 354 if not isinstance(a1inst, (_jump, _eof)):
349 appendinst(_jump(0, a1info._offset + 1)) 355 appendinst(_jump(0, a1info._offset + 1))
350 # Patch instruction at a1, which makes our patch live. 356 # Patch instruction at a1, which makes our patch live.
351 self._program[a1info._offset] = _jump(0, oldproglen) 357 self._program[a1info._offset] = _jump(0, oldproglen)
352 # For compat with the C version, re-annotate rev so that 358
353 # self.annotateresult is cromulent.. We could fix up the 359 # Update self._lastannotate in place. This serves as a cache to avoid
354 # annotateresult in place (which is how the C version works), 360 # expensive "self.annotate" in this function, when "replacelines" is
355 # but for now we'll pass on that and see if it matters in 361 # used continuously.
356 # practice. 362 if len(self._lastannotate.lines) > a1:
357 self.annotate(max(self._lastannotate.rev, rev)) 363 self._lastannotate.lines[a1]._offset = a1instpc
364 else:
365 assert isinstance(a1inst, _eof)
366 self._lastannotate._eof = a1instpc
367 self._lastannotate.lines[a1:a2] = blineinfos
368 self._lastannotate.rev = max(self._lastannotate.rev, rev)
369
358 if rev > self._maxrev: 370 if rev > self._maxrev:
359 self._maxrev = rev 371 self._maxrev = rev
360 372
361 def annotate(self, rev): 373 def annotate(self, rev):
362 pc = 1 374 pc = 1