From e68ae23ccc9fd91ca2f829b23060e247b3083962 Mon Sep 17 00:00:00 2001 From: stevenknight Date: Wed, 12 Jan 2005 20:51:31 +0000 Subject: [PATCH] Improve --debug=count to get an idea of when different objects are created. git-svn-id: http://scons.tigris.org/svn/scons/trunk@1215 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- doc/man/scons.1 | 8 ++-- src/CHANGES.txt | 6 +++ src/engine/SCons/Debug.py | 4 ++ src/engine/SCons/Script/Main.py | 43 ++++++++++++++------ test/option--debug.py | 39 ------------------- test/option/debug-count.py | 69 +++++++++++++++++++++++++++++++++ test/option/debug-memory.py | 68 ++++++++++++++++++++++++++++++++ test/option/debug-objects.py | 63 ++++++++++++++++++++++++++++++ 8 files changed, 247 insertions(+), 53 deletions(-) create mode 100644 test/option/debug-count.py create mode 100644 test/option/debug-memory.py create mode 100644 test/option/debug-objects.py diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 0074dfb7..be4f9449 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 0b47dd92..b46af630 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 410f3906..0d2d85dd 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 1bfd2482..f39375a9 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 f0114e55..322afda1 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 00000000..37323db4 --- /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 00000000..3c3aebd1 --- /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 00000000..324585e2 --- /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() -- 2.26.2