stream-clone: avoid opening a revlog in case we do not need it
Opening an revlog has a cost, especially if it is inline as we have to scan the
file and construct an index.
To prevent the associated slowdown, we just do a minimal scan to check that an
inline file is still inline, and simply stream the file without creating a
revlog when we can.
This provides a big boost compared to the previous changeset, even if the full
generation is still penalized by the initial gathering of information.
All benchmarks are run on linux with Python 3.10.7.
# benchmark.name = hg.exchange.stream.generate
# benchmark.variants.version = v2
### Compared to the previous changesets
We get a large win all across the board!
# mercurial-2018-08-01-zstd-sparse-revlog
before: 0.250694 seconds
after: 0.105986 seconds (-57.72%)
# pypy-2018-08-01-zstd-sparse-revlog
before: 3.885657 seconds
after: 1.709748 seconds (-56.00%)
# netbeans-2018-08-01-zstd-sparse-revlog
before: 16.679371 seconds
after: 7.687469 seconds (-53.91%)
# mozilla-central-2018-08-01-zstd-sparse-revlog
before: 38.575482 seconds
after: 17.520316 seconds (-54.58%)
# mozilla-try-2019-02-18-zstd-sparse-revlog
before: 81.160994 seconds
after: 37.073753 seconds (-54.32%)
### Compared to 6.4.3
We are still significantly slower than 6.4.3, the extra time is usually twice
slower than the extra time we observe on the locked section, which is a quite
interesting information.
Except for mercurial-central that is much faster. That discrepancy is not really
explained yet.
# mercurial-2018-08-01-zstd-sparse-revlog
6.4.3: 0.072560 seconds
after: 0.105986 seconds (+46.07%) (- 0.03 seconds)
# pypy-2018-08-01-zstd-sparse-revlog
6.4.3: 1.211193 seconds
after: 1.709748 seconds (+41.16%) (-0.45 seconds)
# netbeans-2018-08-01-zstd-sparse-revlog
6.4.3: 4.932843 seconds
after: 7.687469 seconds (+55.84%) (-2.75 seconds)
# mozilla-central-2018-08-01-zstd-sparse-revlog
6.4.3: 34.012226 seconds
after: 17.520316 seconds (-48.49%) (-16.49 seconds)
# mozilla-try-2019-02-18-zstd-sparse-revlog
6.4.3: 23.850555 seconds
after: 37.073753 seconds (+55.44%) (+13.22 seconds)
#!/usr/bin/env python3
#
# check-perf-code - (historical) portability checker for contrib/perf.py
import os
import sys
# write static check patterns here
perfpypats = [
[
(
r'(branchmap|repoview|repoviewutil)\.subsettable',
"use getbranchmapsubsettable() for early Mercurial",
),
(
r'\.(vfs|svfs|opener|sopener)',
"use getvfs()/getsvfs() for early Mercurial",
),
(
r'ui\.configint',
"use getint() instead of ui.configint() for early Mercurial",
),
],
# warnings
[],
]
def modulewhitelist(names):
replacement = [
('.py', ''),
('.c', ''), # trim suffix
('mercurial%s' % '/', ''), # trim "mercurial/" path
]
ignored = {'__init__'}
modules = {}
# convert from file name to module name, and count # of appearances
for name in names:
name = name.strip()
for old, new in replacement:
name = name.replace(old, new)
if name not in ignored:
modules[name] = modules.get(name, 0) + 1
# list up module names, which appear multiple times
whitelist = []
for name, count in modules.items():
if count > 1:
whitelist.append(name)
return whitelist
if __name__ == "__main__":
# in this case, it is assumed that result of "hg files" at
# multiple revisions is given via stdin
whitelist = modulewhitelist(sys.stdin)
assert whitelist, "module whitelist is empty"
# build up module whitelist check from file names given at runtime
perfpypats[0].append(
# this matching pattern assumes importing modules from
# "mercurial" package in the current style below, for simplicity
#
# from mercurial import (
# foo,
# bar,
# baz
# )
(
(
r'from mercurial import [(][a-z0-9, \n#]*\n(?! *%s,|^[ #]*\n|[)])'
% ',| *'.join(whitelist)
),
"import newer module separately in try clause for early Mercurial",
)
)
# import contrib/check-code.py as checkcode
assert 'RUNTESTDIR' in os.environ, "use check-perf-code.py in *.t script"
contribpath = os.path.join(os.environ['RUNTESTDIR'], '..', 'contrib')
sys.path.insert(0, contribpath)
checkcode = __import__('check-code')
# register perf.py specific entry with "checks" in check-code.py
checkcode.checks.append(
('perf.py', r'contrib/perf.py$', '', checkcode.pyfilters, perfpypats)
)
sys.exit(checkcode.main())