Improve --debug=count to get an idea of when different objects are created.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 12 Jan 2005 20:51:31 +0000 (20:51 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 12 Jan 2005 20:51:31 +0000 (20:51 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1215 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Debug.py
src/engine/SCons/Script/Main.py
test/option--debug.py
test/option/debug-count.py [new file with mode: 0644]
test/option/debug-memory.py [new file with mode: 0644]
test/option/debug-objects.py [new file with mode: 0644]

index 0074dfb7698a284f9d5fc14ab2c645d9b84f0526..be4f94498afefcbfc8ee0f39584fba153e749eab 100644 (file)
@@ -510,8 +510,10 @@ specifies what type of debugging:
 
 .TP
 --debug=count
-Print a count of how many objects are created
-of the various classes used internally by SCons.
+Print how many objects are created
+of the various classes used internally by SCons
+before and after reading the SConscript files
+and before and after building targets.
 This only works when run under Python 2.1 or later.
 
 .TP
@@ -547,7 +549,7 @@ recomputing them each time they're needed.
 --debug=memory
 Prints how much memory SCons uses
 before and after reading the SConscript files
-and before and after building.
+and before and after building targets.
 
 .TP
 --debug=objects
index 0b47dd9288ababbb3ee381b1fea59cfe75167423..b46af6301c572f7da7e0dc76f9a08e14c6a1353f 100644 (file)
@@ -178,6 +178,12 @@ RELEASE 0.97 - XXX
 
   - Allow more than one --debug= option to be set at a time.
 
+  - Change --debug=count to report object counts before and after
+    reading SConscript files and before and after building targets.
+
+  - Change --debug=memory output to line up the numbers and to better
+    match (more or less) the headers on the --debug=count columns.
+
   From Wayne Lee:
 
   - Avoid "maximum recursion limit" errors when removing $(-$) pairs
index 410f39066dade665957fc1b8ca8c4c84b4eaba39..0d2d85dd7cc5c6356eaebc976154da8991823b26 100644 (file)
@@ -60,6 +60,10 @@ def string_to_classes(s):
     else:
         return string.split(s)
 
+def fetchLoggedInstances(classes="*"):
+    classnames = string_to_classes(classes)
+    return map(lambda cn: (cn, len(tracked_classes[cn])), classnames)
+  
 def countLoggedInstances(classes, file=sys.stdout):
     for classname in string_to_classes(classes):
         file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
index 1bfd2482caebb906b514c4c9cdf473f4faf55bfc..f39375a9f54ea991982078fbbca86f535290f852 100644 (file)
@@ -241,7 +241,7 @@ class QuestionTask(SCons.Taskmaster.Task):
 # Global variables
 
 keep_going_on_error = 0
-print_count = 0
+count_stats = None
 print_dtree = 0
 print_explanations = 0
 print_includes = 0
@@ -407,7 +407,7 @@ def _SConstruct_exists(dirname=''):
 
 def _set_globals(options):
     global repositories, keep_going_on_error, ignore_errors
-    global print_count, print_dtree
+    global count_stats, print_dtree
     global print_explanations, print_includes, print_memoizer
     global print_objects, print_stacktrace, print_stree
     global print_time, print_tree
@@ -424,7 +424,7 @@ def _set_globals(options):
         pass
     else:
         if "count" in debug_values:
-            print_count = 1
+            count_stats = []
         if "dtree" in debug_values:
             print_dtree = 1
         if "explain" in debug_values:
@@ -918,6 +918,7 @@ def _main(args, parser):
         fs.Repository(rep)
 
     if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
+    if not count_stats is None: count_stats.append(SCons.Debug.fetchLoggedInstances())
 
     progress_display("scons: Reading SConscript files ...")
 
@@ -947,6 +948,7 @@ def _main(args, parser):
     SCons.Node.FS.save_strings(1)
 
     if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
+    if not count_stats is None: count_stats.append(SCons.Debug.fetchLoggedInstances())
 
     fs.chdir(fs.Top)
 
@@ -1076,6 +1078,7 @@ def _main(args, parser):
         SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg)
 
     if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
+    if not count_stats is None: count_stats.append(SCons.Debug.fetchLoggedInstances())
 
     try:
         jobs.run()
@@ -1090,16 +1093,34 @@ def _main(args, parser):
     if not memory_stats is None:
         memory_stats.append(SCons.Debug.memory())
         when = [
-            'before SConscript files',
-            'after SConscript files',
-            'before building',
-            'after building',
+            'before reading SConscript files',
+            'after reading SConscript files',
+            'before building targets',
+            'after building targets',
         ]
         for i in xrange(len(when)):
-            memory_outf.write('Memory %s:  %d\n' % (when[i], memory_stats[i]))
-
-    if print_count:
-        SCons.Debug.countLoggedInstances('*')
+            memory_outf.write('Memory %-32s %12d\n' % (when[i]+':', memory_stats[i]))
+
+    if not count_stats is None:
+        count_stats.append(SCons.Debug.fetchLoggedInstances())
+        stats_table = {}
+        for cs in count_stats:
+            for n in map(lambda t: t[0], cs):
+                stats_table[n] = [0, 0, 0, 0]
+        i = 0
+        for cs in count_stats:
+            for n, c in cs:
+                stats_table[n][i] = c
+            i = i + 1
+        keys = stats_table.keys()
+        keys.sort()
+        print "Object counts:"
+        fmt = "    %7s %7s %7s %7s   %s"
+        print fmt % ("pre-", "post-", "pre-", "post-", "")
+        print fmt % ("read", "read", "build", "build", "Class")
+        for k in keys:
+            r = stats_table[k]
+            print "    %7d %7d %7d %7d   %s" % (r[0], r[1], r[2], r[3], k)
 
     if print_objects:
         SCons.Debug.listLoggedInstances('*')
index f0114e554c04519fe640246b7f7d47cb43886dd4..322afda114d59fd7e8f5726b3b52349bc9e30300 100644 (file)
@@ -269,45 +269,6 @@ assert check(expected_command_time, command_time, 0.01)
 assert check(total_time, sconscript_time+scons_time+command_time, 0.01) 
 assert check(total_time, expected_total_time, 0.1)
 
-try:
-    import resource
-except ImportError:
-    print "Python version has no `resource' module;"
-    print "skipping test of --debug=memory."
-else:
-    ############################
-    # test --debug=memory
-
-    test.run(arguments = "--debug=memory")
-    lines = string.split(test.stdout(), '\n')
-    test.fail_test(re.match(r'Memory before SConscript files:  \d+', lines[-5]) is None)
-    test.fail_test(re.match(r'Memory after SConscript files:  \d+', lines[-4]) is None)
-    test.fail_test(re.match(r'Memory before building:  \d+', lines[-3]) is None)
-    test.fail_test(re.match(r'Memory after building:  \d+', lines[-2]) is None)
-
-try:
-    import weakref
-except ImportError:
-    print "Python version has no `weakref' module;"
-    print "skipping tests of --debug=count and --debug=objects."
-else:
-    ############################
-    # test --debug=count
-    # Just check that object counts for some representative classes
-    # show up in the output.
-    test.run(arguments = "--debug=count")
-    stdout = test.stdout()
-    test.fail_test(re.search('BuilderBase: \d+', stdout) is None)
-    test.fail_test(re.search('FS: \d+', stdout) is None)
-    test.fail_test(re.search('Node: \d+', stdout) is None)
-    test.fail_test(re.search('SConsEnvironment: \d+', stdout) is None)
-
-    ############################
-    # test --debug=objects
-    # Just check that it runs, we're not overly concerned about the actual
-    # output at this point.
-    test.run(arguments = "--debug=objects")
-
 ############################
 # test --debug=presub
 
diff --git a/test/option/debug-count.py b/test/option/debug-count.py
new file mode 100644 (file)
index 0000000..37323db
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that the --debug=count option works.
+"""
+
+import TestSCons
+import sys
+import string
+import re
+import time
+
+test = TestSCons.TestSCons()
+
+try:
+    import weakref
+except ImportError:
+    print "Python version has no `weakref' module;"
+    print "skipping tests of --debug=count."
+    test.pass_test()
+
+
+
+test.write('SConstruct', """
+def cat(target, source, env):
+    open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
+env = Environment(BUILDERS={'Cat':Builder(action=Action(cat))})
+env.Cat('file.out', 'file.in')
+""")
+
+test.write('file.in', "file.in\n")
+
+# Just check that object counts for some representative classes
+# show up in the output.
+test.run(arguments = "--debug=count")
+stdout = test.stdout()
+
+test.fail_test(re.search('\d+ +\d+ +\d+ +\d+   BuilderBase', stdout) is None)
+test.fail_test(re.search('\d+ +\d+ +\d+ +\d+   FS', stdout) is None)
+test.fail_test(re.search('\d+ +\d+ +\d+ +\d+   Node', stdout) is None)
+test.fail_test(re.search('\d+ +\d+ +\d+ +\d+   SConsEnvironment', stdout) is None)
+
+
+
+test.pass_test()
diff --git a/test/option/debug-memory.py b/test/option/debug-memory.py
new file mode 100644 (file)
index 0000000..3c3aebd
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that the --debug=memory option works.
+"""
+
+import TestSCons
+import sys
+import string
+import re
+import time
+
+test = TestSCons.TestSCons()
+
+try:
+    import resource
+except ImportError:
+    print "Python version has no `resource' module;"
+    print "skipping test of --debug=memory."
+    test.pass_test()
+
+
+
+test.write('SConstruct', """
+def cat(target, source, env):
+    open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
+env = Environment(BUILDERS={'Cat':Builder(action=Action(cat))})
+env.Cat('file.out', 'file.in')
+""")
+
+test.write('file.in', "file.in\n")
+
+test.run(arguments = "--debug=memory")
+
+lines = string.split(test.stdout(), '\n')
+
+test.fail_test(re.match(r'Memory before reading SConscript files: +\d+', lines[-5]) is None)
+test.fail_test(re.match(r'Memory after reading SConscript files: +\d+', lines[-4]) is None)
+test.fail_test(re.match(r'Memory before building targets: +\d+', lines[-3]) is None)
+test.fail_test(re.match(r'Memory after building targets: +\d+', lines[-2]) is None)
+
+
+
+test.pass_test()
diff --git a/test/option/debug-objects.py b/test/option/debug-objects.py
new file mode 100644 (file)
index 0000000..324585e
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that the --debug=objects option works.
+"""
+
+import TestSCons
+import sys
+import string
+import re
+import time
+
+test = TestSCons.TestSCons()
+
+try:
+    import weakref
+except ImportError:
+    print "Python version has no `weakref' module;"
+    print "skipping tests of --debug=objects."
+    test.pass_test()
+
+
+
+test.write('SConstruct', """
+def cat(target, source, env):
+    open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
+env = Environment(BUILDERS={'Cat':Builder(action=Action(cat))})
+env.Cat('file.out', 'file.in')
+""")
+
+test.write('file.in', "file.in\n")
+
+# Just check that it runs, we're not overly concerned about the actual
+# output at this point.
+test.run(arguments = "--debug=objects")
+
+
+
+test.pass_test()