From: stevenknight Date: Thu, 24 Mar 2005 12:24:56 +0000 (+0000) Subject: Add a subsystem for collecting stats about how Nodes are handled by the Taskmaster. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=a2b66ecb9f88f9a52a248a27921e3379514185b2;p=scons.git Add a subsystem for collecting stats about how Nodes are handled by the Task git-svn-id: http://scons.tigris.org/svn/scons/trunk@1267 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 494fbc92..d018d150 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -1137,10 +1137,12 @@ def _main(args, parser): 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. + # Dump any development debug info that may have been enabled. + # These are purely for internal debugging during development, so + # there's no need to control the with --debug= options, they're + # controlled by changing the source code.) SCons.Debug.dump_caller_counts() + SCons.Taskmaster.dump_stats() def _exec_main(): all_args = sys.argv[1:] diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index b90bfe1b..7b58f4b8 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -36,6 +36,40 @@ import traceback import SCons.Node import SCons.Errors +# A subsystem for recording stats about how different Nodes are handled by +# the main Taskmaster loop. There's no external control here (no need for +# a --debug= option); enabled it by changing the value of CollectStats. + +CollectStats = None + +class Stats: + def __init__(self): + self.considered = 0 + self.already_handled = 0 + self.problem = 0 + self.child_failed = 0 + self.not_started = 0 + self.not_built = 0 + self.side_effects = 0 + self.build = 0 + +StatsNodes = [] + +fmt = "%(considered)5d" \ + " %(already_handled)5d" \ + " %(problem)5d" \ + " %(child_failed)5d" \ + " %(not_started)5d" \ + " %(not_built)5d" \ + " %(side_effects)5d" \ + " %(build)5d" \ + " " + +def dump_stats(): + StatsNodes.sort(lambda a, b: cmp(a.name, b.name)) + for n in StatsNodes: + print (fmt % n.stats.__dict__) + str(n) + class Task: """Default SCons build engine task. @@ -280,8 +314,18 @@ class Taskmaster: node = self.candidates.pop() state = node.get_state() + if CollectStats: + if not hasattr(node, 'stats'): + node.stats = Stats() + StatsNodes.append(node) + S = node.stats + S.considered = S.considered + 1 + else: + S = None + # Skip this node if it has already been handled: if not state in [ SCons.Node.no_state, SCons.Node.stack ]: + if S: S.already_handled = S.already_handled + 1 continue # Mark this node as being on the execution stack: @@ -306,6 +350,7 @@ class Taskmaster: # raise the exception when the Task is "executed." self.ready_exc = sys.exc_info() self.ready = node + if S: S.problem = S.problem + 1 break # Skip this node if any of its children have failed. This @@ -314,6 +359,7 @@ class Taskmaster: # by a *previous* descent of an earlier top-level target. if filter(lambda I: I[0] == SCons.Node.failed, childinfo): node.set_state(SCons.Node.failed) + if S: S.child_failed = S.child_failed + 1 continue # Detect dependency cycles: @@ -360,6 +406,7 @@ class Taskmaster: self.candidates.append(node) not_started.reverse() self.candidates.extend(self.order(not_started)) + if S: S.not_started = S.not_started + 1 continue not_built = filter(lambda I: I[0] <= SCons.Node.executing, derived_children) @@ -376,6 +423,7 @@ class Taskmaster: # put back on the candidates list when appropriate. self.pending.append(node) node.set_state(SCons.Node.pending) + if S: S.not_built = S.built + 1 continue # Skip this node if it has side-effects that are @@ -386,11 +434,13 @@ class Taskmaster: 0): self.pending.append(node) node.set_state(SCons.Node.pending) + if S: S.side_effects = S.side_effects + 1 continue # The default when we've gotten through all of the checks above: # this node is ready to be built. self.ready = node + if S: S.build = S.build + 1 break def next_task(self):