From 8d7efe0bde47b784128f4e81c9bec3b39da77e1e Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Mon, 10 Aug 2015 23:05:14 -0500 Subject: [PATCH] Ensure performance-sensitive identifiers are interned --- loopy/frontend/fortran/translator.py | 7 ++++-- loopy/kernel/__init__.py | 22 ++++++++++++++---- loopy/kernel/creation.py | 33 +++++++++++++++++++-------- loopy/kernel/data.py | 34 +++++++++++++++++++++++++++- loopy/kernel/tools.py | 2 +- loopy/tools.py | 10 ++++++++ 6 files changed, 91 insertions(+), 17 deletions(-) diff --git a/loopy/frontend/fortran/translator.py b/loopy/frontend/fortran/translator.py index 97005cab6..8293035a9 100644 --- a/loopy/frontend/fortran/translator.py +++ b/loopy/frontend/fortran/translator.py @@ -25,6 +25,7 @@ THE SOFTWARE. import re import six +from six.moves import intern import loopy as lp import numpy as np @@ -221,7 +222,7 @@ class F2LoopyTranslator(FTreeWalkerBase): def add_expression_instruction(self, lhs, rhs): scope = self.scope_stack[-1] - new_id = "insn%d" % self.insn_id_counter + new_id = intern("insn%d" % self.insn_id_counter) self.insn_id_counter += 1 if self.auto_dependencies and scope.previous_instruction_id: @@ -447,7 +448,7 @@ class F2LoopyTranslator(FTreeWalkerBase): def map_IfThen(self, node): scope = self.scope_stack[-1] - cond_name = "loopy_cond%d" % self.condition_id_counter + cond_name = intern("loopy_cond%d" % self.condition_id_counter) self.condition_id_counter += 1 assert cond_name not in scope.type_map @@ -543,6 +544,8 @@ class F2LoopyTranslator(FTreeWalkerBase): loop_var_suffix += 1 loopy_loop_var = loop_var + "_%d" % loop_var_suffix + loopy_loop_var = intern(loopy_loop_var) + # }}} space = isl.Space.create_from_names(isl.DEFAULT_CONTEXT, diff --git a/loopy/kernel/__init__.py b/loopy/kernel/__init__.py index 16695e0ad..121a516c1 100644 --- a/loopy/kernel/__init__.py +++ b/loopy/kernel/__init__.py @@ -351,7 +351,18 @@ class LoopKernel(RecordWithoutPickling): for id_str in generate_unique_names(based_on): if id_str not in used_ids: - return id_str + return intern(id_str) + + def all_group_names(self): + result = set() + for insn in self.instructions: + result.update(insn.groups) + result.update(insn.conflicts_with_groups) + + return frozenset(result) + + def get_group_name_generator(self): + return _UniqueVarNameGenerator(self.all_group_names()) def get_var_descriptor(self, name): try: @@ -577,7 +588,8 @@ class LoopKernel(RecordWithoutPickling): def all_inames(self): result = set() for dom in self.domains: - result.update(dom.get_var_names(dim_type.set)) + result.update( + intern(n) for n in dom.get_var_names(dim_type.set)) return frozenset(result) @memoize_method @@ -588,7 +600,8 @@ class LoopKernel(RecordWithoutPickling): for dom in self.domains: result.update(set(dom.get_var_names(dim_type.param)) - all_inames) - return frozenset(result) + from loopy.tools import intern_frozenset_of_ids + return intern_frozenset_of_ids(result) def outer_params(self, domains=None): if domains is None: @@ -600,7 +613,8 @@ class LoopKernel(RecordWithoutPickling): all_inames.update(dom.get_var_names(dim_type.set)) all_params.update(dom.get_var_names(dim_type.param)) - return all_params-all_inames + from loopy.tools import intern_frozenset_of_ids + return intern_frozenset_of_ids(all_params-all_inames) @memoize_method def all_insn_inames(self): diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index e891f0626..556bc3a74 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -26,6 +26,7 @@ THE SOFTWARE. import numpy as np +from loopy.tools import intern_frozenset_of_ids from loopy.symbolic import IdentityMapper, WalkMapper from loopy.kernel.data import ( InstructionBase, ExpressionInstruction, SubstitutionRule) @@ -33,7 +34,7 @@ import islpy as isl from islpy import dim_type import six -from six.moves import range, zip +from six.moves import range, zip, intern import re import sys @@ -216,7 +217,7 @@ def parse_insn(insn): opt_value = option[equal_idx+1:].strip() if opt_key == "id": - insn_id = opt_value + insn_id = intern(opt_value) elif opt_key == "id_prefix": insn_id = UniqueName(opt_value) elif opt_key == "priority": @@ -235,17 +236,18 @@ def parse_insn(insn): insn_deps_is_final = True opt_value = (opt_value[1:]).strip() - insn_deps = frozenset(dep.strip() for dep in opt_value.split(":") + insn_deps = frozenset( + intern(dep.strip()) for dep in opt_value.split(":") if dep.strip()) elif opt_key == "groups": insn_groups = frozenset( - grp.strip() for grp in opt_value.split(":") + intern(grp.strip()) for grp in opt_value.split(":") if grp.strip()) elif opt_key == "conflicts": conflicts_with_groups = frozenset( - grp.strip() for grp in opt_value.split(":") + intern(grp.strip()) for grp in opt_value.split(":") if grp.strip()) elif opt_key == "inames": @@ -255,10 +257,10 @@ def parse_insn(insn): else: forced_iname_deps_is_final = True - forced_iname_deps = frozenset(opt_value.split(":")) + forced_iname_deps = intern_frozenset_of_ids(opt_value.split(":")) elif opt_key == "if": - predicates = frozenset(opt_value.split(":")) + predicates = intern_frozenset_of_ids(opt_value.split(":")) elif opt_key == "tags": tags = tuple( @@ -284,7 +286,10 @@ def parse_insn(insn): "be variable or subscript" % lhs) return ExpressionInstruction( - id=insn_id, + id=( + intern(insn_id) + if not isinstance(insn_id, (type(None), UniqueName)) + else None), insn_deps=insn_deps, insn_deps_is_final=insn_deps_is_final, groups=insn_groups, @@ -326,7 +331,17 @@ def parse_insn(insn): def parse_if_necessary(insn, defines): if isinstance(insn, InstructionBase): - yield insn, [] + yield insn.copy( + id=intern(insn.id) if insn.id is not None else None, + insn_deps=frozenset(intern(dep) for dep in insn.insn_deps), + groups=frozenset(intern(grp) for grp in insn.groups), + conflicts_with_groups=frozenset( + intern(grp) for grp in insn.conflicts_with_groups), + forced_iname_deps=frozenset( + intern(iname) for iname in insn.forced_iname_deps), + predicates=frozenset( + intern(pred) for pred in insn.predicates), + ), [] return elif not isinstance(insn, str): raise TypeError("Instructions must be either an Instruction " diff --git a/loopy/kernel/data.py b/loopy/kernel/data.py index b88929358..2d9faa4cf 100644 --- a/loopy/kernel/data.py +++ b/loopy/kernel/data.py @@ -25,6 +25,7 @@ THE SOFTWARE. """ +from six.moves import intern import numpy as np from pytools import Record, memoize_method from loopy.kernel.array import ArrayBase @@ -185,6 +186,8 @@ def parse_tag(tag): class KernelArgument(Record): def __init__(self, **kwargs): + kwargs["name"] = intern(kwargs.pop("name")) + dtype = kwargs.pop("dtype", None) if isinstance(dtype, np.dtype): @@ -339,7 +342,7 @@ class TemporaryVariable(ArrayBase): if base_indices is None: base_indices = (0,) * len(shape) - ArrayBase.__init__(self, name=name, + ArrayBase.__init__(self, name=intern(name), dtype=dtype, shape=shape, dim_tags=dim_tags, order="C", base_indices=base_indices, is_local=is_local, @@ -512,6 +515,9 @@ class InstructionBase(Record): forced_iname_deps_is_final, forced_iname_deps, priority, boostable, boostable_into, predicates, tags): + if insn_deps is None: + insn_deps = frozenset() + if groups is None: groups = frozenset() @@ -531,6 +537,17 @@ class InstructionBase(Record): if tags is None: tags = () + # Periodically reenable these and run the tests to ensure all + # performance-relevant identifiers are interned. + # + # from loopy.tools import is_interned + # assert is_interned(id) + # assert all(is_interned(dep) for dep in insn_deps) + # assert all(is_interned(grp) for grp in groups) + # assert all(is_interned(grp) for grp in conflicts_with_groups) + # assert all(is_interned(iname) for iname in forced_iname_deps) + # assert all(is_interned(pred) for pred in predicates) + assert isinstance(forced_iname_deps, frozenset) assert isinstance(insn_deps, frozenset) or insn_deps is None assert isinstance(groups, frozenset) @@ -650,6 +667,21 @@ class InstructionBase(Record): # }}} + def __setstate__(self, val): + super(InstructionBase, self).__setstate__(val) + + from loopy.tools import intern_frozenset_of_ids + + self.id = intern(self.id) + self.insn_deps = intern_frozenset_of_ids(self.insn_deps) + self.groups = intern_frozenset_of_ids(self.groups) + self.conflicts_with_groups = ( + intern_frozenset_of_ids(self.conflicts_with_groups)) + self.forced_iname_deps = ( + intern_frozenset_of_ids(self.forced_iname_deps)) + self.predicates = ( + intern_frozenset_of_ids(self.predicates)) + # }}} diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index b59c40731..e811935bb 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -204,7 +204,7 @@ def find_all_insn_inames(kernel): # current inames refer to. if par in kernel.all_inames(): - inames_new.add(par) + inames_new.add(intern(par)) # If something writes the bounds of a loop in which I'm # sitting, I had better be in the inames that the writer is diff --git a/loopy/tools.py b/loopy/tools.py index e734417d6..861d15568 100644 --- a/loopy/tools.py +++ b/loopy/tools.py @@ -30,6 +30,7 @@ from loopy.symbolic import WalkMapper as LoopyWalkMapper from pymbolic.mapper.persistent_hash import ( PersistentHashWalkMapper as PersistentHashWalkMapperBase) import six # noqa +from six.moves import intern if six.PY2: @@ -216,4 +217,13 @@ def remove_common_indentation(code, require_leading_newline=True, # }}} + +def is_interned(s): + return s is None or intern(s) is s + + +def intern_frozenset_of_ids(fs): + return frozenset(intern(s) for s in fs) + + # vim: foldmethod=marker -- GitLab