summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2005-01-12 20:51:31 (GMT)
committerSteven Knight <knight@baldmt.com>2005-01-12 20:51:31 (GMT)
commit14dce368b0856c2dbaf7ccd7b10934ea7bcef46b (patch)
treecc4084606a3aa14592e3f8b48fcab9fd5e3df2c5
parent063a53965a67233506b2e11b561231ce27c4bb07 (diff)
downloadSCons-14dce368b0856c2dbaf7ccd7b10934ea7bcef46b.zip
SCons-14dce368b0856c2dbaf7ccd7b10934ea7bcef46b.tar.gz
SCons-14dce368b0856c2dbaf7ccd7b10934ea7bcef46b.tar.bz2
Improve --debug=count to get an idea of when different objects are created.
-rw-r--r--doc/man/scons.18
-rw-r--r--src/CHANGES.txt6
-rw-r--r--src/engine/SCons/Debug.py4
-rw-r--r--src/engine/SCons/Script/Main.py43
-rw-r--r--test/option--debug.py39
-rw-r--r--test/option/debug-count.py69
-rw-r--r--test/option/debug-memory.py68
-rw-r--r--test/option/debug-objects.py63
8 files changed, 247 insertions, 53 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 0074dfb..be4f944 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -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
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 0b47dd9..b46af63 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -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
diff --git a/src/engine/SCons/Debug.py b/src/engine/SCons/Debug.py
index 410f390..0d2d85d 100644
--- a/src/engine/SCons/Debug.py
+++ b/src/engine/SCons/Debug.py
@@ -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])))
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index 1bfd248..f39375a 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -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('*')
diff --git a/test/option--debug.py b/test/option--debug.py
index f0114e5..322afda 100644
--- a/test/option--debug.py
+++ b/test/option--debug.py
@@ -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
index 0000000..37323db
--- /dev/null
+++ b/test/option/debug-count.py
@@ -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
index 0000000..3c3aebd
--- /dev/null
+++ b/test/option/debug-memory.py
@@ -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
index 0000000..324585e
--- /dev/null
+++ b/test/option/debug-objects.py
@@ -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()