Mercurial > hg
view mercurial/help/diffs.txt @ 33171:6d678ab1b10d
revlog: C implementation of delta chain resolution
I've seen revlog._deltachain() appear in a number of performance
profiles. I suspect there are 2 reasons for this:
1. Delta chain resolution performs many index lookups, thus triggering
population of index tuples. Creating possibly tens of thousands of
PyObject will have overhead.
2. Delta chain resolution is a tight loop.
By moving delta chain resolution to C, we can defer instantiation
of full index entry tuples and make the loop faster courtesy of
not running in Python.
We can measure the impact to delta chain resolution via
`hg perflogrevision` using the mozilla-central repo with a recent
manifest having delta chain length of 33726:
$ hg perfrevlogrevision -m 364895
! full
! wall 0.367585 comb 0.370000 user 0.340000 sys 0.030000 (best of 27)
! wall 0.357581 comb 0.360000 user 0.350000 sys 0.010000 (best of 28)
! deltachain
! wall 0.010644 comb 0.010000 user 0.010000 sys 0.000000 (best of 270)
! wall 0.000292 comb 0.000000 user 0.000000 sys 0.000000 (best of 8729)
$ hg perfrevlogrevision --cache -m 364895
! deltachain
! wall 0.003904 comb 0.000000 user 0.000000 sys 0.000000 (best of 712)
! wall 0.000284 comb 0.000000 user 0.000000 sys 0.000000 (best of 9926)
The first test measures savings from both not instantiating index
entries and moving to C. The second test (which doesn't clear the
index caches) essentially isolates the benefits of moving from Python
to C. It still shows a 13.7x speedup (versus 36.4x). And there are
multiple milliseconds of savings within the critical path for resolving
revision data. I think that justifies the existence of C code.
A more striking example of the benefits of this change can be
demonstrated by timing `hg debugdeltachain -m` for the mozilla-central
repo:
$ time hg debugdeltachain -m > /dev/null
before: 1057.4s
after: 503.3s
PyPy2.7 5.8.0: 220.0s
It's worth noting that the C code isn't as optimal as it could be.
We're still instantiating a new PyObject for every revision. A future
optimization would be to reuse the PyObject on the cached index tuple.
We could potentially also get wins by using a memory array of raw
integers. There is also room for a delta chain cache on revlog
instances. Of course, the best optimization is to implement revlog
reading outside of Python so Python doesn't need to be concerned
about the relatively expensive index entries and operations on them.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sun, 25 Jun 2017 12:41:34 -0700 |
parents | ebfc46929f3e |
children |
line wrap: on
line source
Mercurial's default format for showing changes between two versions of a file is compatible with the unified format of GNU diff, which can be used by GNU patch and many other standard tools. While this standard format is often enough, it does not encode the following information: - executable status and other permission bits - copy or rename information - changes in binary files - creation or deletion of empty files Mercurial also supports the extended diff format from the git VCS which addresses these limitations. The git diff format is not produced by default because a few widespread tools still do not understand this format. This means that when generating diffs from a Mercurial repository (e.g. with :hg:`export`), you should be careful about things like file copies and renames or other things mentioned above, because when applying a standard diff to a different repository, this extra information is lost. Mercurial's internal operations (like push and pull) are not affected by this, because they use an internal binary format for communicating changes. To make Mercurial produce the git extended diff format, use the --git option available for many commands, or set 'git = True' in the [diff] section of your configuration file. You do not need to set this option when importing diffs in this format or using them in the mq extension.