Commits

Anonymous committed 67f0408

Optimize out N*M suffix matching in Builder.py.

Comments (0)

Files changed (4)

 
 def fetch_counts(fname):
     contents = open(fname).read()
-    m = re.search('\nObject counts:\n(.*)\n[^\s]', contents, re.S)
+    m = re.search('\nObject counts:(\n\s[^\n]*)*', contents, re.S)
     lines = m.group().split('\n')
     list = [l.split() for l in lines if re.match('\s+\d', l)]
     d = {}

src/engine/SCons/Builder.py

 
         src_suffixes = self.src_suffixes(env)
 
+        def match_src_suffix(node, src_suffixes=src_suffixes):
+            # This reaches directly into the Node.name attribute (instead
+            # of using an accessor function) for performance reasons.
+            return filter(lambda s, n=node.name:
+                                 n[-len(s):] == s,
+                          src_suffixes)
+
         for snode in slist:
-            for srcsuf in src_suffixes:
-                if str(snode)[-len(srcsuf):] == srcsuf and sdict.has_key(srcsuf):
-                    tgt = sdict[srcsuf]._execute(env, None, [snode], overwarn)
-                    # If the subsidiary Builder returned more than one target,
-                    # then filter out any sources that this Builder isn't
-                    # capable of building.
-                    if len(tgt) > 1:
-                        tgt = filter(lambda x, self=self, suf=src_suffixes, e=env:
-                                     self.splitext(SCons.Util.to_String(x),e)[1] in suf,
-                                     tgt)
-                    final_sources.extend(tgt)
-                    snode = None
-                    break
-            if snode:
+            name = snode.name
+            match = match_src_suffix(snode)
+            if match:
+                try:
+                    bld = sdict[match[0]]
+                except KeyError:
+                    final_sources.append(snode)
+                else:
+                    tlist = bld._execute(env, None, [snode], overwarn)
+                    # If the subsidiary Builder returned more than one
+                    # target, then filter out any sources that this
+                    # Builder isn't capable of building.
+                    if len(tlist) > 1:
+                        tlist = filter(match_src_suffix, tlist)
+                    final_sources.extend(tlist)
+            else:
                 final_sources.append(snode)
-                
+
         return BuilderBase._execute(self, env, target, final_sources, overwarn)
 
     def get_src_builders(self, env):

src/engine/SCons/Debug.py

         def memory():
             res = resource.getrusage(resource.RUSAGE_SELF)
             return res[4]
+
+
+
+caller_dicts = {}
+
+def caller(back=0):
+    import traceback
+    tb = traceback.extract_stack(limit=3+back)
+    key = tb[1][:3]
+    try:
+        entry = caller_dicts[key]
+    except KeyError:
+        entry = caller_dicts[key] = {}
+    key = tb[0][:3]
+    try:
+        entry[key] = entry[key] + 1
+    except KeyError:
+        entry[key] = 1
+
+def dump_caller_counts(file=sys.stdout):
+    keys = caller_dicts.keys()
+    keys.sort()
+    for k in keys:
+        file.write("Callers of %s:%d(%s):\n" % func_shorten(k))
+        counts = caller_dicts[k]
+        callers = counts.keys()
+        callers.sort()
+        for c in callers:
+            #file.write("    counts[%s] = %s\n" % (c, counts[c]))
+            t = ((counts[c],) + func_shorten(c))
+            file.write("    %6d %s:%d(%s)\n" % t)
+
+shorten_list = [
+    ( '/scons/SCons/',          1),
+    ( '/src/engine/SCons/',     1),
+    ( '/usr/lib/python',        0),
+]
+
+def func_shorten(func_tuple):
+    f = func_tuple[0]
+    for t in shorten_list:
+        i = string.find(f, t[0])
+        if i >= 0:
+            if t[1]:
+                i = i + len(t[0])
+            f = f[i:]
+            break
+    return (f,)+func_tuple[1:]

src/engine/SCons/Script/Main.py

         print "Memoizer (memory cache) hits and misses:"
         SCons.Memoize.Dump()
 
+    # Dump any caller counts.  This is purely for internal debugging
+    # during development, so there's no need to control it with a
+    # --debug= option.
+    SCons.Debug.dump_caller_counts()
+
 def _exec_main():
     all_args = sys.argv[1:]
     try: