diff options
author | Steven Knight <knight@baldmt.com> | 2003-01-06 03:54:25 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2003-01-06 03:54:25 (GMT) |
commit | 6702e9dce5182eaa012da9dc511fcf85cf205049 (patch) | |
tree | 08fd77ca8579ba8426241b560202cd8f9a20c3f8 | |
parent | 51974ccdc1ee8340c54f8fa02670c554d20ef157 (diff) | |
download | SCons-6702e9dce5182eaa012da9dc511fcf85cf205049.zip SCons-6702e9dce5182eaa012da9dc511fcf85cf205049.tar.gz SCons-6702e9dce5182eaa012da9dc511fcf85cf205049.tar.bz2 |
Performance improvement: cut down on Proxy.__getattr__ calls.
-rw-r--r-- | src/CHANGES.txt | 3 | ||||
-rw-r--r-- | src/engine/SCons/Builder.py | 2 | ||||
-rw-r--r-- | src/engine/SCons/BuilderTests.py | 2 | ||||
-rw-r--r-- | src/engine/SCons/Environment.py | 6 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 16 | ||||
-rw-r--r-- | src/engine/SCons/Node/__init__.py | 19 | ||||
-rw-r--r-- | src/engine/SCons/Script/__init__.py | 12 | ||||
-rw-r--r-- | src/engine/SCons/Sig/SigTests.py | 13 | ||||
-rw-r--r-- | src/engine/SCons/Sig/__init__.py | 4 | ||||
-rw-r--r-- | src/engine/SCons/Taskmaster.py | 2 | ||||
-rw-r--r-- | src/engine/SCons/TaskmasterTests.py | 3 |
11 files changed, 54 insertions, 28 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 7cb4eb9..88ee9e8 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -31,6 +31,9 @@ RELEASE 0.10 - XXX - Fix SCons not exiting with the appropriate status on build errors (and probably in other situations). + - Significant performance improvement from using a more efficient + check, throughout the code, for whether a Node has a Builder. + From Steve Leblanc: - Add a Clean() method to support removing user-specified targets diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 2f5df7f..15358c1 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -149,7 +149,7 @@ def _init_nodes(builder, env, overrides, tlist, slist): for t in tlist: if t.side_effect: raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t) - if t.builder is not None: + if t.has_builder(): if t.env != env: raise UserError, "Two different environments were specified for the same target: %s"%str(t) elif t.overrides != overrides: diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 5906314..9905eb9 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -116,6 +116,8 @@ class BuilderTestCase(unittest.TestCase): return self.name def builder_set(self, builder): self.builder = builder + def has_builder(self): + return not self.builder is None def env_set(self, env, safe=0): self.env = env def add_source(self, source): diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 8861a99..a5672ae 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -360,9 +360,9 @@ class Environment: for side_effect in side_effects: # A builder of 1 means the node is supposed to appear - # buildable without actually having a builder, so we allow - # it to be a side effect as well. - if side_effect.builder is not None and side_effect.builder != 1: + # buildable without actually having a builder, so we allow + # it to be a side effect as well. + if side_effect.has_builder() and side_effect.builder != 1: raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect) side_effect.add_source(targets) side_effect.side_effect = 1 diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 0569dea..826307b 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -182,7 +182,7 @@ class Entry(SCons.Node.Node): def __str__(self): """A FS node's string representation is its path name.""" - if self.duplicate or self.builder: + if self.duplicate or self.has_builder(): return self.path return self.srcnode().path @@ -513,7 +513,7 @@ class FS: # This is usually the case with BuildDir(). # We only want to find pre-existing files. if rnode.exists() and \ - (isinstance(rnode, Dir) or not rnode.builder): + (isinstance(rnode, Dir) or not rnode.has_builder()): return rnode except TypeError: pass # Wrong type of node. @@ -558,7 +558,7 @@ class FS: # want it to show up in the build tree. This is usually the # case with BuildDir(). We only want to find pre-existing files. if (not must_exist or rnode.exists()) and \ - (not rnode.builder or isinstance(rnode, Dir)): + (not rnode.has_builder() or isinstance(rnode, Dir)): ret.append(rnode) except TypeError: pass # Wrong type of node. @@ -819,7 +819,7 @@ class File(Entry): in the .sconsign file. """ - if self.builder: + if self.has_builder(): if SCons.Sig.build_signature: if not hasattr(self, 'bsig'): self.set_bsig(calc.bsig(self.rfile())) @@ -904,14 +904,14 @@ class File(Entry): """Prepare for this file to be created.""" def missing(node): - return not node.builder and not node.linked and not node.rexists() + return not node.has_builder() and not node.linked and not node.rexists() missing_sources = filter(missing, self.children()) if missing_sources: desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self) raise SCons.Errors.StopError, desc if self.exists(): - if self.builder and not self.precious: + if self.has_builder() and not self.precious: Unlink(self, None, None) if hasattr(self, '_exists'): delattr(self, '_exists') @@ -931,7 +931,7 @@ class File(Entry): def exists(self): # Duplicate from source path if we are set up to do this. - if self.duplicate and not self.builder and not self.linked: + if self.duplicate and not self.has_builder() and not self.linked: src=self.srcnode().rfile() if src.exists() and src.abspath != self.abspath: self._createDir() @@ -1008,7 +1008,7 @@ def find_file(filename, paths, node_factory = default_fs.File): try: node = node_factory(filename, dir) # Return true of the node exists or is a derived node. - if node.builder or \ + if node.has_builder() or \ (isinstance(node, SCons.Node.FS.Entry) and node.exists()): retval = node break diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index e5aae5c..3bafb9c 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -114,7 +114,7 @@ class Node: so only do thread safe stuff here. Do thread unsafe stuff in built(). """ - if not self.builder: + if not self.has_builder(): return None action_list = self.builder.get_actions() if not action_list: @@ -160,6 +160,19 @@ class Node: def builder_set(self, builder): self.builder = builder + def has_builder(self): + """Return whether this Node has a builder or not. + + In Boolean tests, this turns out to be a *lot* more efficient + than simply examining the builder attribute directly ("if + node.builder: ..."). When the builder attribute is examined + directly, it ends up calling __getattr__ for both the __len__ + and __nonzero__ attributes on instances of our Builder Proxy + class(es), generating a bazillion extra calls and slowing + things down immensely. + """ + return not self.builder is None + def builder_sig_adapter(self): """Create an adapter for calculating a builder's signature. @@ -190,7 +203,7 @@ class Node: if not self.implicit is None: return self.implicit = [] - if not self.builder: + if not self.has_builder(): return if implicit_cache and not implicit_deps_changed: @@ -243,7 +256,7 @@ class Node: in the .sconsign file. """ - if self.builder: + if self.has_builder(): if SCons.Sig.build_signature: if not hasattr(self, 'bsig'): self.set_bsig(calc.bsig(self)) diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index 93f4795..ca6536f 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -75,9 +75,9 @@ class BuildTask(SCons.Taskmaster.Task): def execute(self): target = self.targets[0] if target.get_state() == SCons.Node.up_to_date: - if self.top and target.builder: + if self.top and target.has_builder(): display('scons: "%s" is up to date.' % str(target)) - elif target.builder and not hasattr(target.builder, 'status'): + elif target.has_builder() and not hasattr(target.builder, 'status'): if print_time: start_time = time.time() SCons.Taskmaster.Task.execute(self) @@ -100,7 +100,7 @@ class BuildTask(SCons.Taskmaster.Task): def executed(self): t = self.targets[0] - if self.top and not t.builder and not t.side_effect: + if self.top and not t.has_builder() and not t.side_effect: if not t.exists(): sys.stderr.write("scons: *** Do not know how to make target `%s'." % t) if not keep_going_on_error: @@ -145,7 +145,7 @@ class BuildTask(SCons.Taskmaster.Task): class CleanTask(SCons.Taskmaster.Task): """An SCons clean task.""" def show(self): - if self.targets[0].builder or self.targets[0].side_effect: + if self.targets[0].has_builder() or self.targets[0].side_effect: display("Removed " + str(self.targets[0])) if SCons.Script.SConscript.clean_targets.has_key(str(self.targets[0])): files = SCons.Script.SConscript.clean_targets[str(self.targets[0])] @@ -153,7 +153,7 @@ class CleanTask(SCons.Taskmaster.Task): SCons.Utils.fs_delete(str(f), 0) def remove(self): - if self.targets[0].builder or self.targets[0].side_effect: + if self.targets[0].has_builder() or self.targets[0].side_effect: for t in self.targets: try: removed = t.remove() @@ -217,7 +217,7 @@ def get_all_children(node): return node.all_children(None) def get_derived_children(node): children = node.all_children(None) - return filter(lambda x: x.builder, children) + return filter(lambda x: x.has_builder(), children) def _scons_syntax_error(e): """Handle syntax errors. Print out a message and show where the error diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py index ccd5897..57c5a51 100644 --- a/src/engine/SCons/Sig/SigTests.py +++ b/src/engine/SCons/Sig/SigTests.py @@ -59,6 +59,9 @@ class DummyNode: self.oldbsig = 0 self.oldcsig = 0 + def has_builder(self): + return self.builder + def get_contents(self): # a file that doesn't exist has no contents: assert self.exists() @@ -97,7 +100,7 @@ class DummyNode: return None def calc_signature(self, calc): - if self.builder: + if self.has_builder(): return calc.bsig(self) else: return calc.csig(self) @@ -212,7 +215,7 @@ class SigTestBase: for node in nodes: self.failUnless(not current(calc, node), - "none of the nodes should be current") + "node %s should not be current" % node.path) # simulate a build: self.files[1].modify('built', 222) @@ -230,7 +233,7 @@ class SigTestBase: for node in nodes: self.failUnless(current(calc, node), - "all of the nodes should be current") + "node %s should be current" % node.path) def test_modify(self): @@ -278,7 +281,7 @@ class SigTestBase: for node in nodes: self.failUnless(current(calc, node), - "all of the nodes should be current") + "node %s should be current" % node.path) class MD5TestCase(unittest.TestCase, SigTestBase): @@ -311,6 +314,8 @@ class CalcTestCase(unittest.TestCase): self.ignore = [] self.builder = None self.use_signature = 1 + def has_builder(self): + return not self.builder is None def children(self): return filter(lambda x, i=self.ignore: x not in i, self.kids) def all_children(self): diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py index 5de89fa..4fe9423 100644 --- a/src/engine/SCons/Sig/__init__.py +++ b/src/engine/SCons/Sig/__init__.py @@ -263,7 +263,7 @@ class Calculator: what's wanted. """ sigs = map(lambda n, c=self: n.calc_signature(c), node.children()) - if node.builder: + if node.has_builder(): sigs.append(self.module.signature(node.builder_sig_adapter())) bsig = self.module.collect(filter(lambda x: not x is None, sigs)) @@ -320,7 +320,7 @@ class Calculator: """ oldtime, oldbsig, oldcsig = node.get_prevsiginfo() - if not node.builder and node.get_timestamp() == oldtime: + if not node.has_builder() and node.get_timestamp() == oldtime: return 1 return self.module.current(newsig, oldbsig) diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index eec50bf..74703f2 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -213,7 +213,7 @@ class Taskmaster: # Add non-derived files that have not been built # to the candidates list: def derived(node): - return (node.builder or node.side_effect) and node.get_state() == None + return (node.has_builder() or node.side_effect) and node.get_state() == None derived = filter(derived, children) if derived: derived.reverse() diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index d8bcc4f..79ff11b 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -57,6 +57,9 @@ class Node: global built_text built_text = self.name + " built" + def has_builder(self): + return not self.builder is None + def built(self): global built_text built_text = built_text + " really" |