summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Scanner/__init__.py
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2004-09-21 17:38:54 (GMT)
committerSteven Knight <knight@baldmt.com>2004-09-21 17:38:54 (GMT)
commit50c6d9c6698a79ec2c0299c61b6ffdd2b27e921b (patch)
treeb49818b9f0745e7613d12de400205d889baa3224 /src/engine/SCons/Scanner/__init__.py
parente2995450dd47b5e106c16ee5768de7f6964a9408 (diff)
downloadSCons-50c6d9c6698a79ec2c0299c61b6ffdd2b27e921b.zip
SCons-50c6d9c6698a79ec2c0299c61b6ffdd2b27e921b.tar.gz
SCons-50c6d9c6698a79ec2c0299c61b6ffdd2b27e921b.tar.bz2
Performance optimization when caching include files for a search path. (Eric Frias)
Diffstat (limited to 'src/engine/SCons/Scanner/__init__.py')
-rw-r--r--src/engine/SCons/Scanner/__init__.py48
1 files changed, 40 insertions, 8 deletions
diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py
index 8ea4223..f865efc 100644
--- a/src/engine/SCons/Scanner/__init__.py
+++ b/src/engine/SCons/Scanner/__init__.py
@@ -33,6 +33,7 @@ import re
import SCons.Node.FS
import SCons.Sig
+import SCons.UserTuple
import SCons.Util
@@ -52,6 +53,29 @@ def Scanner(function, *args, **kw):
else:
return apply(Base, (function,) + args, kw)
+# Important, important, important performance optimization:
+#
+# The paths of Nodes returned from a FindPathDirs will be used to index
+# a dictionary that caches the values, so we don't have to look up the
+# same path over and over and over. If FindPathDir returns just a tuple,
+# though, then the time it takes to compute the hash of the tuple grows
+# proportionally to the length of the tuple itself--and some people can
+# have very, very long strings of include directories...
+#
+# The solution is to wrap the tuple in an object, a UserTuple class
+# whose *id()* our caller can use to cache the appropriate value.
+# This means we have to guarantee that these ids genuinely represent
+# unique values, which we do by maintaining our own cache that maps the
+# expensive-to-hash tuple values to the easy-to-hash UniqueUserTuple
+# values that our caller uses.
+#
+# *Major* kudos to Eric Frias and his colleagues for finding this.
+class UniqueUserTuple(SCons.UserTuple.UserTuple):
+ def __hash__(self):
+ return id(self)
+
+PathCache = {}
+
class FindPathDirs:
"""A class to bind a specific *PATH variable name and the fs object
to a function that will return all of the *path directories."""
@@ -64,10 +88,16 @@ class FindPathDirs:
except KeyError:
return ()
- return tuple(self.fs.Rsearchall(env.subst_path(path),
- must_exist = 0,
- clazz = SCons.Node.FS.Dir,
- cwd = dir))
+ path_tuple = tuple(self.fs.Rsearchall(env.subst_path(path),
+ must_exist = 0,
+ clazz = SCons.Node.FS.Dir,
+ cwd = dir))
+ try:
+ return PathCache[path_tuple]
+ except KeyError:
+ path_UserTuple = UniqueUserTuple(path_tuple)
+ PathCache[path_tuple] = path_UserTuple
+ return path_UserTuple
class Base:
"""
@@ -188,7 +218,7 @@ class Base:
return cmp(self.__dict__, other.__dict__)
def __hash__(self):
- return hash(repr(self))
+ return id(self)
def add_skey(self, skey):
"""Add a skey to the list of skeys"""
@@ -269,7 +299,9 @@ class Classic(Current):
apply(Current.__init__, (self,) + args, kw)
def find_include(self, include, source_dir, path):
- n = SCons.Node.FS.find_file(include, (source_dir,) + path, self.fs.File)
+ n = SCons.Node.FS.find_file(include,
+ (source_dir,) + tuple(path),
+ self.fs.File)
return n, include
def scan(self, node, env, path=()):
@@ -330,10 +362,10 @@ class ClassicCPP(Classic):
def find_include(self, include, source_dir, path):
if include[0] == '"':
n = SCons.Node.FS.find_file(include[1],
- (source_dir,) + path,
+ (source_dir,) + tuple(path),
self.fs.File)
else:
n = SCons.Node.FS.find_file(include[1],
- path + (source_dir,),
+ tuple(path) + (source_dir,),
self.fs.File)
return n, include[1]