Mercurial > public > mercurial-scm > hg-stable
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 |