Mercurial > hg
view hgdemandimport/demandimportpy3.py @ 41247:a89b20a49c13
rust-cpython: using MissingAncestors from Python code
As precedently done with LazyAncestors on cpython.rs, we test for the
presence of the 'rustext' module.
incrementalmissingrevs() has two callers within the Mercurial core:
`setdiscovery.partialdiscovery` and the `only()` revset.
This move shows a significant discovery performance improvement
in cases where the baseline is slow: using perfdiscovery on the PyPy
repos, prepared with `contrib/discovery-helper <repo> 50 100`, we
get averaged medians of 403ms with the Rust version vs 742ms without
(about 45% better).
But there are still indications that performance can be worse in cases
the baseline is fast, possibly due to the conversion from Python to
Rust and back becoming the bottleneck. We could measure this on
mozilla-central in cases were the delta is just a few changesets.
This requires confirmation, but if that's the reason, then an
upcoming `partialdiscovery` fully in Rust should solve the problem.
Differential Revision: https://phab.mercurial-scm.org/D5551
author | Georges Racinet <georges.racinet@octobus.net> |
---|---|
date | Fri, 30 Nov 2018 14:35:57 +0100 |
parents | 670eb4fa1b86 |
children | adb636392b3f |
line wrap: on
line source
# demandimportpy3 - global demand-loading of modules for Mercurial # # Copyright 2017 Facebook Inc. # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. """Lazy loading for Python 3.6 and above. This uses the new importlib finder/loader functionality available in Python 3.5 and up. The code reuses most of the mechanics implemented inside importlib.util, but with a few additions: * Allow excluding certain modules from lazy imports. * Expose an interface that's substantially the same as demandimport for Python 2. This also has some limitations compared to the Python 2 implementation: * Much of the logic is per-package, not per-module, so any packages loaded before demandimport is enabled will not be lazily imported in the future. In practice, we only expect builtins to be loaded before demandimport is enabled. """ # This line is unnecessary, but it satisfies test-check-py3-compat.t. from __future__ import absolute_import import contextlib import importlib.abc import importlib.machinery import importlib.util import sys _deactivated = False class _lazyloaderex(importlib.util.LazyLoader): """This is a LazyLoader except it also follows the _deactivated global and the ignore list. """ def exec_module(self, module): """Make the module load lazily.""" if _deactivated or module.__name__ in ignores: self.loader.exec_module(module) else: super().exec_module(module) # This is 3.6+ because with Python 3.5 it isn't possible to lazily load # extensions. See the discussion in https://bugs.python.org/issue26186 for more. _extensions_loader = _lazyloaderex.factory( importlib.machinery.ExtensionFileLoader) _bytecode_loader = _lazyloaderex.factory( importlib.machinery.SourcelessFileLoader) _source_loader = _lazyloaderex.factory(importlib.machinery.SourceFileLoader) def _makefinder(path): return importlib.machinery.FileFinder( path, # This is the order in which loaders are passed in in core Python. (_extensions_loader, importlib.machinery.EXTENSION_SUFFIXES), (_source_loader, importlib.machinery.SOURCE_SUFFIXES), (_bytecode_loader, importlib.machinery.BYTECODE_SUFFIXES), ) ignores = set() def init(ignoreset): global ignores ignores = ignoreset def isenabled(): return _makefinder in sys.path_hooks and not _deactivated def disable(): try: while True: sys.path_hooks.remove(_makefinder) except ValueError: pass def enable(): sys.path_hooks.insert(0, _makefinder) @contextlib.contextmanager def deactivated(): # This implementation is a bit different from Python 2's. Python 3 # maintains a per-package finder cache in sys.path_importer_cache (see # PEP 302). This means that we can't just call disable + enable. # If we do that, in situations like: # # demandimport.enable() # ... # from foo.bar import mod1 # with demandimport.deactivated(): # from foo.bar import mod2 # # mod2 will be imported lazily. (The converse also holds -- whatever finder # first gets cached will be used.) # # Instead, have a global flag the LazyLoader can use. global _deactivated demandenabled = isenabled() if demandenabled: _deactivated = True try: yield finally: if demandenabled: _deactivated = False