summaryrefslogtreecommitdiff
path: root/third_party/waf/waflib/extras/mem_reducer.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/waf/waflib/extras/mem_reducer.py')
-rw-r--r--third_party/waf/waflib/extras/mem_reducer.py110
1 files changed, 110 insertions, 0 deletions
diff --git a/third_party/waf/waflib/extras/mem_reducer.py b/third_party/waf/waflib/extras/mem_reducer.py
new file mode 100644
index 00000000000..e97c8d7272c
--- /dev/null
+++ b/third_party/waf/waflib/extras/mem_reducer.py
@@ -0,0 +1,110 @@
+#! /usr/bin/env python
+# encoding: UTF-8
+
+"""
+This tool can help to reduce the memory usage in very large builds featuring many tasks with after/before attributes.
+It may also improve the overall build time by decreasing the amount of iterations over tasks.
+
+Usage:
+def options(opt):
+ opt.load('mem_reducer')
+"""
+
+import itertools
+from waflib import Utils, Task, Runner
+
+class SetOfTasks(object):
+ """Wraps a set and a task which has a list of other sets.
+ The interface is meant to mimic the interface of set. Add missing functions as needed.
+ """
+ def __init__(self, owner):
+ self._set = owner.run_after
+ self._owner = owner
+
+ def __iter__(self):
+ for g in self._owner.run_after_groups:
+ #print len(g)
+ for task in g:
+ yield task
+ for task in self._set:
+ yield task
+
+ def add(self, obj):
+ self._set.add(obj)
+
+ def update(self, obj):
+ self._set.update(obj)
+
+def set_precedence_constraints(tasks):
+ cstr_groups = Utils.defaultdict(list)
+ for x in tasks:
+ x.run_after = SetOfTasks(x)
+ x.run_after_groups = []
+ x.waiting_sets = []
+
+ h = x.hash_constraints()
+ cstr_groups[h].append(x)
+
+ # create sets which can be reused for all tasks
+ for k in cstr_groups.keys():
+ cstr_groups[k] = set(cstr_groups[k])
+
+ # this list should be short
+ for key1, key2 in itertools.combinations(cstr_groups.keys(), 2):
+ group1 = cstr_groups[key1]
+ group2 = cstr_groups[key2]
+ # get the first entry of the set
+ t1 = next(iter(group1))
+ t2 = next(iter(group2))
+
+ # add the constraints based on the comparisons
+ if Task.is_before(t1, t2):
+ for x in group2:
+ x.run_after_groups.append(group1)
+ for k in group1:
+ k.waiting_sets.append(group1)
+ elif Task.is_before(t2, t1):
+ for x in group1:
+ x.run_after_groups.append(group2)
+ for k in group2:
+ k.waiting_sets.append(group2)
+
+Task.set_precedence_constraints = set_precedence_constraints
+
+def get_out(self):
+ tsk = self.out.get()
+ if not self.stop:
+ self.add_more_tasks(tsk)
+ self.count -= 1
+ self.dirty = True
+
+ # shrinking sets
+ try:
+ ws = tsk.waiting_sets
+ except AttributeError:
+ pass
+ else:
+ for k in ws:
+ try:
+ k.remove(tsk)
+ except KeyError:
+ pass
+
+ return tsk
+Runner.Parallel.get_out = get_out
+
+def skip(self, tsk):
+ tsk.hasrun = Task.SKIPPED
+
+ # shrinking sets
+ try:
+ ws = tsk.waiting_sets
+ except AttributeError:
+ pass
+ else:
+ for k in ws:
+ try:
+ k.remove(tsk)
+ except KeyError:
+ pass
+Runner.Parallel.skip = skip