Skip to content

Commit 0ce21ac

Browse files
bonzinijpakkane
authored andcommitted
arglist: optimize flush_pre_post(), and __iadd__() with it
Unless an argument is marked as Dedup.OVERRIDDEN, pre_flush_set and post_flush_set will always be empty and the loops in flush_pre_post() will not be doing anything interesting: for a in self.pre: dedup = self._can_dedup(a) if a not in pre_flush_set: # This just makes new a copy of self.pre new.append(a) if dedup is Dedup.OVERRIDDEN: # this never happens pre_flush_set.add(a) for a in reversed(self.post): dedup = self._can_dedup(a) if a not in post_flush_set: # Here self.post is reversed twice post_flush.appendleft(a) if dedup is Dedup.OVERRIDDEN: # this never happens post_flush_set.add(a) new.extend(post_flush) In this case it's possible to avoid expensive calls and loops, instead relying as much on Python builtins as possible. Track whether any options have that flag and if not just concatenate pre, _container and post. Before: ncalls tottime cumtime 45127 0.251 4.530 arglist.py:142(__iter__) 81866 3.623 5.013 arglist.py:108(flush_pre_post) 76618 3.793 5.338 arglist.py:273(__iadd__) After: 35647 0.156 0.627 arglist.py:160(__iter__) 78998 2.627 3.603 arglist.py:116(flush_pre_post) 73774 3.605 5.049 arglist.py:292(__iadd__) The time in __iadd__ is reduced because it calls __iter__, which flushes pre and post. Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 25abe40 commit 0ce21ac

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

mesonbuild/arglist.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,25 @@ def __init__(self, compiler: T.Union['Compiler', 'StaticLinker'],
104104
# pass the underlying list to list() directly, instead of an iterator
105105
iterable = iterable._container
106106
self._container: T.List[str] = list(iterable) if iterable is not None else []
107+
107108
self.pre: T.Deque[str] = collections.deque()
108109
self.post: T.Deque[str] = collections.deque()
110+
self.needs_override_check: bool = False
109111

110112
# Flush the saved pre and post list into the _container list
111113
#
112114
# This correctly deduplicates the entries after _can_dedup definition
113115
# Note: This function is designed to work without delete operations, as deletions are worsening the performance a lot.
114116
def flush_pre_post(self) -> None:
117+
if not self.needs_override_check:
118+
if self.pre:
119+
self._container[0:0] = self.pre
120+
self.pre.clear()
121+
if self.post:
122+
self._container.extend(self.post)
123+
self.post.clear()
124+
return
125+
115126
new: T.List[str] = []
116127
pre_flush_set: T.Set[str] = set()
117128
post_flush: T.Deque[str] = collections.deque()
@@ -133,17 +144,15 @@ def flush_pre_post(self) -> None:
133144

134145
#pre and post will overwrite every element that is in the container
135146
#only copy over args that are in _container but not in the post flush or pre flush set
136-
if pre_flush_set or post_flush_set:
137-
for a in self._container:
138-
if a not in post_flush_set and a not in pre_flush_set:
139-
new.append(a)
140-
else:
141-
new.extend(self._container)
147+
for a in self._container:
148+
if a not in post_flush_set and a not in pre_flush_set:
149+
new.append(a)
142150
new.extend(post_flush)
143151

144152
self._container = new
145153
self.pre.clear()
146154
self.post.clear()
155+
self.needs_override_check = False
147156

148157
def __iter__(self) -> T.Iterator[str]:
149158
# see also __init__, where this method is essentially inlined
@@ -295,6 +304,8 @@ def __iadd__(self, args: T.Iterable[str]) -> 'CompilerArgs':
295304
# Argument already exists and adding a new instance is useless
296305
if arg in self._container or arg in self.pre or arg in self.post:
297306
continue
307+
elif dedup is Dedup.OVERRIDDEN:
308+
self.needs_override_check = True
298309
if self._should_prepend(arg):
299310
tmp_pre.appendleft(arg)
300311
else:

0 commit comments

Comments
 (0)