Speed up string expansion. Cache find_file() results in the Memoizer.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Tue, 8 Mar 2005 18:05:41 +0000 (18:05 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Tue, 8 Mar 2005 18:05:41 +0000 (18:05 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1249 fdb21ef1-2011-0410-befe-b5e4ea1792b1

bin/bench.py [new file with mode: 0644]
src/engine/SCons/Node/FS.py
src/engine/SCons/Util.py

diff --git a/bin/bench.py b/bin/bench.py
new file mode 100644 (file)
index 0000000..7d9e2ba
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+#
+# A script for timing snippets of Python code.
+
+import time
+
+Now = time.time
+#Now = time.clock       # better on Windows, some UNIX/Linux systems
+
+# How many times each snippet of code will be run by the functions
+# to gather the time (the "inner loop").
+
+Iterations = 10000
+
+# How many times we'll run each function to collect its aggregate time
+# and try to average out timing differences induced by system performance
+# (the "outer loop").
+
+Runs = 10
+
+# The functions containing the code snippets to test and compare.
+# This script will test any function whose name begins with the string
+# "Func" and assumes that they all get passed the same arguments.
+# Each function should put its snippet within a block:
+#
+#       for i in IterationList:
+#
+# So that (as much as possible) we're testing just the code itself,
+# not Python function call overhead.
+
+def Func1(var, gvars, lvars):
+    for i in IterationList:
+        try:
+            x = lvars[var]
+        except KeyError:
+            try:
+                x = gvars[var]
+            except KeyError:
+                x = ''
+
+def Func2(var, gvars, lvars):
+    for i in IterationList:
+        if lvars.has_key(var):
+            x = lvars[var]
+        else:
+            try:
+                x = gvars[var]
+            except KeyError:
+                x = ''
+
+def Func3(var, gvars, lvars):
+    for i in IterationList:
+        if lvars.has_key(var):
+            x = lvars[var]
+        elif gvars.has_key(var):
+            x = gvars[var]
+        else:
+            x = ''
+
+def Func4(var, gvars, lvars):
+    for i in IterationList:
+        try:
+            x = eval(var, gvars, lvars)
+        except NameError:
+            x = ''
+
+# Data to pass to the functions on each run.  Each entry is a
+# three-element tuple:
+#
+#   (
+#       "Label to print describing this data run",
+#       ('positional', 'arguments'),
+#       {'keyword' : 'arguments'},
+#   ),
+
+Data = [
+    (
+        "Neither in gvars or lvars",
+        ('x', {}, {}),
+        {},
+    ),
+    (
+        "Missing from lvars, found in gvars",
+        ('x', {'x':1}, {}),
+        {},
+    ),
+    (
+        "Found in lvars",
+        ('x', {'x':1}, {'x':2}),
+        {},
+    ),
+]
+
+
+
+IterationList = [None]
+
+def timer(func, *args, **kw):
+    global IterationList
+    IterationList = [None] * Iterations
+    results = []
+    for i in range(Runs):
+        start = Now()
+        func(*args, **kw)
+        finish = Now()
+        results.append((finish - start) / Iterations)
+    return results
+
+def display(label, results):
+    print '    ' + label + ':'
+    print '    ',
+    for r in results:
+        print "%.3f" % (r * 1e6),
+    print
+
+def display(label, results):
+    total = reduce(lambda x, y: x+y, results, 0.0)
+    print "    %8.3f" % ((total * 1e6) / len(results)), ':', label
+
+func_names = filter(lambda x: x.startswith('Func'), locals().keys())
+func_names.sort()
+
+for f in func_names:
+    func = locals()[f]
+    print f + ':'
+
+    for label, args, kw in Data:
+        r = apply(timer, (func,)+args, kw)
+        display(label, r)
index 9dfd355b7eccf07e40624568a010df75ee12d0bb..336ba1f0a2a44b5b166869727bc65037007bc40a 100644 (file)
@@ -1892,6 +1892,7 @@ def find_file(filename, paths, verbose=None):
 
     Only the first file found is returned, and none is returned
     if no file is found.
+    __cacheable__
     """
     if verbose:
         if not SCons.Util.is_String(verbose):
index 2ca487f2a775fc0d08aa8fd16705ea685449b67a..e76087d8c003c6ece2da063a3a5dcdca6690340c 100644 (file)
@@ -582,15 +582,6 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
             self.conv = conv
             self.gvars = gvars
 
-        def expand_var_once(self, var, lvars):
-            try:
-                return lvars[var]
-            except KeyError:
-                try:
-                    return self.gvars[var]
-                except KeyError:
-                    return ''
-
         def expand(self, s, lvars):
             """Expand a single "token" as necessary, returning an
             appropriate string containing the expansion.
@@ -629,7 +620,12 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
                                 else:
                                     raise SCons.Errors.UserError, "Syntax error `%s' trying to evaluate `%s'" % (e,s)
                         else:
-                            s = self.expand_var_once(key, lvars)
+                            if lvars.has_key(key):
+                                s = lvars[key]
+                            elif self.gvars.has_key(key):
+                                s = self.gvars[key]
+                            else:
+                                return ''
 
                         # Before re-expanding the result, handle
                         # recursive expansion by copying the local