From 42667fe7fa1182759f0d2bf3b9637038d345dc78 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 1 Jun 2023 22:36:42 +0200 Subject: Memoize a few hot functions during module file generation (#37739) --- lib/spack/spack/modules/common.py | 4 +--- lib/spack/spack/modules/lmod.py | 5 +++++ lib/spack/spack/tengine.py | 16 ++++++++-------- lib/spack/spack/test/relocate.py | 2 +- lib/spack/spack/test/tengine.py | 2 +- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/spack/spack/modules/common.py b/lib/spack/spack/modules/common.py index 278038510a..ef3f751471 100644 --- a/lib/spack/spack/modules/common.py +++ b/lib/spack/spack/modules/common.py @@ -170,11 +170,9 @@ def merge_config_rules(configuration, spec): Returns: dict: actions to be taken on the spec passed as an argument """ - # Construct a dictionary with the actions we need to perform on the spec passed as a parameter - spec_configuration = {} # The keyword 'all' is always evaluated first, all the others are # evaluated in order of appearance in the module file - spec_configuration.update(copy.deepcopy(configuration.get("all", {}))) + spec_configuration = copy.deepcopy(configuration.get("all", {})) for constraint, action in configuration.items(): if spec.satisfies(constraint): if hasattr(constraint, "override") and constraint.override: diff --git a/lib/spack/spack/modules/lmod.py b/lib/spack/spack/modules/lmod.py index 64c8c49b7e..0abead05b6 100644 --- a/lib/spack/spack/modules/lmod.py +++ b/lib/spack/spack/modules/lmod.py @@ -134,6 +134,7 @@ class LmodConfiguration(BaseConfiguration): return configuration(self.name).get("filter_hierarchy_specs", {}) @property + @lang.memoized def hierarchy_tokens(self): """Returns the list of tokens that are part of the modulefile hierarchy. 'compiler' is always present. @@ -158,6 +159,7 @@ class LmodConfiguration(BaseConfiguration): return tokens @property + @lang.memoized def requires(self): """Returns a dictionary mapping all the requirements of this spec to the actual provider. 'compiler' is always present among the @@ -224,6 +226,7 @@ class LmodConfiguration(BaseConfiguration): return available @property + @lang.memoized def missing(self): """Returns the list of tokens that are not available.""" return [x for x in self.hierarchy_tokens if x not in self.available] @@ -317,6 +320,7 @@ class LmodFileLayout(BaseFileLayout): return parts @property + @lang.memoized def unlocked_paths(self): """Returns a dictionary mapping conditions to a list of unlocked paths. @@ -428,6 +432,7 @@ class LmodContext(BaseContext): return self.conf.missing @tengine.context_property + @lang.memoized def unlocked_paths(self): """Returns the list of paths that are unlocked unconditionally.""" layout = make_layout(self.spec, self.conf.name, self.conf.explicit) diff --git a/lib/spack/spack/tengine.py b/lib/spack/spack/tengine.py index 86c5235a57..6a77e6becf 100644 --- a/lib/spack/spack/tengine.py +++ b/lib/spack/spack/tengine.py @@ -4,7 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import itertools import textwrap -from typing import List +from typing import List, Optional, Tuple import llnl.util.lang @@ -66,17 +66,17 @@ class Context(metaclass=ContextMeta): return dict(d) -def make_environment(dirs=None): - """Returns an configured environment for template rendering.""" +@llnl.util.lang.memoized +def make_environment(dirs: Optional[Tuple[str, ...]] = None): + """Returns a configured environment for template rendering.""" + # Import at this scope to avoid slowing Spack startup down + import jinja2 + if dirs is None: # Default directories where to search for templates builtins = spack.config.get("config:template_dirs", ["$spack/share/spack/templates"]) extensions = spack.extensions.get_template_dirs() - dirs = [canonicalize_path(d) for d in itertools.chain(builtins, extensions)] - - # avoid importing this at the top level as it's used infrequently and - # slows down startup a bit. - import jinja2 + dirs = tuple(canonicalize_path(d) for d in itertools.chain(builtins, extensions)) # Loader for the templates loader = jinja2.FileSystemLoader(dirs) diff --git a/lib/spack/spack/test/relocate.py b/lib/spack/spack/test/relocate.py index 1b14ad9fbb..a0553d4422 100644 --- a/lib/spack/spack/test/relocate.py +++ b/lib/spack/spack/test/relocate.py @@ -62,7 +62,7 @@ def source_file(tmpdir, is_relocatable): src = tmpdir.join("relocatable.c") shutil.copy(template_src, str(src)) else: - template_dirs = [os.path.join(spack.paths.test_path, "data", "templates")] + template_dirs = (os.path.join(spack.paths.test_path, "data", "templates"),) env = spack.tengine.make_environment(template_dirs) template = env.get_template("non_relocatable.c") text = template.render({"prefix": spack.store.layout.root}) diff --git a/lib/spack/spack/test/tengine.py b/lib/spack/spack/test/tengine.py index 3ade233160..95362c33fa 100644 --- a/lib/spack/spack/test/tengine.py +++ b/lib/spack/spack/test/tengine.py @@ -71,7 +71,7 @@ class TestTengineEnvironment(object): """Tests the template retrieval mechanism hooked into config files""" # Check the directories are correct template_dirs = spack.config.get("config:template_dirs") - template_dirs = [canonicalize_path(x) for x in template_dirs] + template_dirs = tuple([canonicalize_path(x) for x in template_dirs]) assert len(template_dirs) == 3 env = tengine.make_environment(template_dirs) -- cgit v1.2.3-60-g2f50