diff options
author | Marcel Hollerbach <mail@marcel-hollerbach.de> | 2020-01-17 19:16:57 +0100 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2020-03-01 19:27:49 +0200 |
commit | 4524088d386d2e2315d8fef6ffedc11d8e9a394a (patch) | |
tree | 60ba6c5be3099694136908bebb2a7f2c0112a4b9 | |
parent | 25cbcb19a9208ebf8f5cde3f8ecb91df0a2dfebf (diff) | |
download | meson-4524088d386d2e2315d8fef6ffedc11d8e9a394a.zip meson-4524088d386d2e2315d8fef6ffedc11d8e9a394a.tar.gz meson-4524088d386d2e2315d8fef6ffedc11d8e9a394a.tar.bz2 |
CompilerArgs: make lookup faster
in order to deduplicate arguments as much as possible, we need to check
if a argument is already part of the list. Which is quite slow because
we are checking 3 lists for that.
In smaller projects this might be not of interested. However, in efl
things are quite "heavy", alone generating the ninja file took 40 sec..
16 sec. are spent in __iadd__ of CompilerArgs.
What this patch does to speed this all up is:
1. We only check if a element is in post when we know that it must be in
post same for pre.
2. the checks for if we already do contain a specific value are now done
via a dict, and not via the list.
This overall brings the time from 16 sec. spent in __iadd__ to 9 sec. in
__iadd__.
Another possible solution for all this is to have a internal structure
of CompileArgs of trees, so you have the "basic" layer of arguments
where the position does not matter. Additionally, you have two stacks of
lists, the pre stack and the post stack, duplicates can then be checked
when itereting, which would safe another ~4s in terms of efl. However, i
do not have time for this undertaking right now.
-rw-r--r-- | mesonbuild/compilers/compilers.py | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 37cf2e0..2a29716 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -15,6 +15,7 @@ import contextlib, os.path, re, tempfile import collections.abc import typing as T +from functools import lru_cache from ..linkers import StaticLinker, GnuLikeDynamicLinkerMixin, SolarisDynamicLinker from .. import coredata @@ -445,6 +446,9 @@ class CompilerArgs(collections.abc.MutableSequence): iterable: T.Optional[T.Iterable[str]] = None): self.compiler = compiler self.__container = list(iterable) if iterable is not None else [] # type: T.List[str] + self.__seen_args = set() + for arg in self.__container: + self.__seen_args.add(arg) @T.overload # noqa: F811 def __getitem__(self, index: int) -> str: # noqa: F811 @@ -467,20 +471,27 @@ class CompilerArgs(collections.abc.MutableSequence): def __setitem__(self, index, value) -> None: # noqa: F811 self.__container[index] = value + for v in value: + self.__seen_args.add(v) def __delitem__(self, index: T.Union[int, slice]) -> None: + value = self.__container[index] del self.__container[index] + if value in self.__seen_args and value in self.__container: # this is also honoring that you can have duplicated entries + self.__seen_args.remove(value) def __len__(self) -> int: return len(self.__container) def insert(self, index: int, value: str) -> None: self.__container.insert(index, value) + self.__seen_args.add(value) def copy(self) -> 'CompilerArgs': return CompilerArgs(self.compiler, self.__container.copy()) @classmethod + @lru_cache(maxsize=None) def _can_dedup(cls, arg): ''' Returns whether the argument can be safely de-duped. This is dependent @@ -526,6 +537,7 @@ class CompilerArgs(collections.abc.MutableSequence): return 0 @classmethod + @lru_cache(maxsize=None) def _should_prepend(cls, arg): if arg.startswith(cls.prepend_prefixes): return True @@ -588,6 +600,7 @@ class CompilerArgs(collections.abc.MutableSequence): self.append(arg) else: self.__container.append(arg) + self.__seen_args.add(arg) def extend_direct(self, iterable: T.Iterable[str]) -> None: ''' @@ -619,6 +632,7 @@ class CompilerArgs(collections.abc.MutableSequence): Add two CompilerArgs while taking into account overriding of arguments and while preserving the order of arguments as much as possible ''' + this_round_added = set() # a dict that contains a value, when the value was added this round pre = [] # type: T.List[str] post = [] # type: T.List[str] if not isinstance(args, collections.abc.Iterable): @@ -630,20 +644,25 @@ class CompilerArgs(collections.abc.MutableSequence): dedup = self._can_dedup(arg) if dedup == 1: # Argument already exists and adding a new instance is useless - if arg in self or arg in pre or arg in post: + if arg in self.__seen_args or arg in pre or arg in post: continue + should_prepend = self._should_prepend(arg) if dedup == 2: # Remove all previous occurrences of the arg and add it anew - if arg in self: + if arg in self.__seen_args and arg not in this_round_added: #if __seen_args contains arg as well as this_round_added, then its not yet part in self. self.remove(arg) - if arg in pre: - pre.remove(arg) - if arg in post: - post.remove(arg) - if self._should_prepend(arg): + if should_prepend: + if arg in pre: + pre.remove(arg) + else: + if arg in post: + post.remove(arg) + if should_prepend: pre.append(arg) else: post.append(arg) + self.__seen_args.add(arg) + this_round_added.add(arg) # Insert at the beginning self[:0] = pre # Append to the end |