Fix some performance problems with the --implicit-cache option. (Anthony Roach)
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Tue, 11 Feb 2003 11:27:07 +0000 (11:27 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Tue, 11 Feb 2003 11:27:07 +0000 (11:27 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@587 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Sig/__init__.py

index 068dc3d6e17990c8a47183cef7791d24d6e3d71b..a8c621dd80117c893a07fd270672bd0a0163e9af 100644 (file)
@@ -96,6 +96,8 @@ RELEASE 0.11 - XXX
   - Allow the same object files on Win32 to be linked into either
     shared or static libraries.
 
+  - Cache implicit cache values when using --implicit-cache.
+
 
 
 RELEASE 0.10 - Thu, 16 Jan 2003 04:11:46 -0600
index 2057797f7d2e16ac93c28069668b3fb4ee234bfa..651d2803424304b305947ad1c23b3f1504d947de 100644 (file)
@@ -850,34 +850,26 @@ class File(Entry):
         else:
             return 0
 
-    def calc_signature(self, calc):
+    def calc_signature(self, calc, cache=None):
         """
         Select and calculate the appropriate build signature for a File.
 
         self - the File node
         calc - the signature calculation module
+        cache - alternate node to use for the signature cache
         returns - the signature
-
-        This method does not store the signature in the node or
-        in the .sconsign file.
         """
 
         if self.has_builder():
             if SCons.Sig.build_signature:
-                if not hasattr(self, 'bsig'):
-                    self.set_bsig(calc.bsig(self.rfile()))
-                return self.get_bsig()
+                return calc.bsig(self.rfile(), self)
             else:
-                if not hasattr(self, 'csig'):
-                    self.set_csig(calc.csig(self.rfile()))
-                return self.get_csig()
+                return calc.csig(self.rfile(), self)
         elif not self.rexists():
             return None
         else:
-            if not hasattr(self, 'csig'):
-                self.set_csig(calc.csig(self.rfile()))
-            return self.get_csig()
-
+            return calc.csig(self.rfile(), self)
+        
     def store_csig(self):
         self.dir.sconsign().set_csig(self.name, self.get_csig())
 
index e1bc8f1c0e3214964f4f8f58a13eb3097991aa24..600c4781d444a968a97703cee95513fb7cf85d36 100644 (file)
@@ -255,6 +255,22 @@ class Node:
 
         return deps
 
+    # cache used to make implicit_factory fast.
+    implicit_factory_cache = {}
+    
+    def implicit_factory(self, path):
+        """
+        Turn a cache implicit dependency path into a node.
+        This is called so many times that doing caching
+        here is a significant perforamnce boost.
+        """
+        try:
+            return self.implicit_factory_cache[path]
+        except KeyError:
+            n = self.builder.source_factory(path)
+            self.implicit_factory_cache[path] = n
+            return n
+
     def scan(self):
         """Scan this node's dependents for implicit dependencies."""
         # Don't bother scanning non-derived files, because we don't
@@ -269,7 +285,7 @@ class Node:
         if implicit_cache and not implicit_deps_changed:
             implicit = self.get_stored_implicit()
             if implicit is not None:
-                implicit = map(self.builder.source_factory, implicit)
+                implicit = map(self.implicit_factory, implicit)
                 self._add_child(self.implicit, implicit)
                 calc = SCons.Sig.default_calc
                 if implicit_deps_unchanged or calc.current(self, calc.bsig(self)):
@@ -306,33 +322,25 @@ class Node:
             return
         self.env = env
 
-    def calc_signature(self, calc):
+    def calc_signature(self, calc, cache=None):
         """
         Select and calculate the appropriate build signature for a node.
 
         self - the node
         calc - the signature calculation module
+        cache - alternate node to use for the signature cache
         returns - the signature
-
-        This method does not store the signature in the node or
-        in the .sconsign file.
         """
 
         if self.has_builder():
             if SCons.Sig.build_signature:
-                if not hasattr(self, 'bsig'):
-                    self.set_bsig(calc.bsig(self))
-                return self.get_bsig()
+                return calc.bsig(self, cache)
             else:
-                if not hasattr(self, 'csig'):
-                    self.set_csig(calc.csig(self))
-                return self.get_csig()
+                return calc.csig(self, cache)
         elif not self.exists():
             return None
         else:
-            if not hasattr(self, 'csig'):
-                self.set_csig(calc.csig(self))
-            return self.get_csig()
+            return calc.csig(self, cache)
 
     def get_bsig(self):
         """Get the node's build signature (based on the signatures
index 939f36f9afb07422f541a8e72634c7b08a666e03..196d06541d789633ff1df6eb82cdb7dbfc6e39e5 100644 (file)
@@ -249,12 +249,13 @@ class Calculator:
         self.module = module
         self.max_drift = max_drift
 
-    def bsig(self, node):
+    def bsig(self, node, cache=None):
         """
         Generate a node's build signature, the digested signatures
         of its dependency files and build information.
 
         node - the node whose sources will be collected
+        cache - alternate node to use for the signature cache
         returns - the build signature
 
         This no longer handles the recursive descent of the
@@ -262,27 +263,50 @@ class Calculator:
         already built and updated by someone else, if that's
         what's wanted.
         """
-        sigs = map(lambda n, c=self: n.calc_signature(c), node.children())
+
+        if cache is None: cache = node
+
+        bsig = cache.get_bsig()
+        if bsig is not None:
+            return bsig
+
+        children = node.children()
+
+        # double check bsig, because the call to childre() above may
+        # have set it:
+        bsig = cache.get_bsig()
+        if bsig is not None:
+            return bsig
+        
+        sigs = map(lambda n, c=self: n.calc_signature(c), children)
         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))
 
-        node.set_bsig(bsig)
+        cache.set_bsig(bsig)
 
         # don't store the bsig here, because it isn't accurate until
         # the node is actually built.
 
         return bsig
 
-    def csig(self, node):
+    def csig(self, node, cache=None):
         """
         Generate a node's content signature, the digested signature
         of its content.
 
         node - the node
+        cache - alternate node to use for the signature cache
         returns - the content signature
         """
+
+        if cache is None: cache = node
+
+        csig = cache.get_csig()
+        if csig is not None:
+            return csig
+        
         if self.max_drift >= 0:
             info = node.get_prevsiginfo()
         else:
@@ -295,12 +319,12 @@ class Calculator:
             csig = info[2]
             # Set the csig here so it doesn't get recalculated unnecessarily
             # and so it's set when the .sconsign file gets written
-            node.set_csig(csig)
+            cache.set_csig(csig)
         else:
             csig = self.module.signature(node)
             # Set the csig here so it doesn't get recalculated unnecessarily
             # and so it's set when the .sconsign file gets written
-            node.set_csig(csig)
+            cache.set_csig(csig)
 
             if self.max_drift >= 0 and (time.time() - mtime) > self.max_drift:
                 node.store_csig()