| Index: scons-2.0.1/script/scons-time
|
| ===================================================================
|
| --- scons-2.0.1/script/scons-time (revision 0)
|
| +++ scons-2.0.1/script/scons-time (revision 0)
|
| @@ -0,0 +1,1544 @@
|
| +#!/usr/bin/env python
|
| +#
|
| +# scons-time - run SCons timings and collect statistics
|
| +#
|
| +# A script for running a configuration through SCons with a standard
|
| +# set of invocations to collect timing and memory statistics and to
|
| +# capture the results in a consistent set of output files for display
|
| +# and analysis.
|
| +#
|
| +
|
| +#
|
| +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation
|
| +#
|
| +# 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.
|
| +from __future__ import division
|
| +from __future__ import nested_scopes
|
| +
|
| +__revision__ = "src/script/scons-time.py 5134 2010/08/16 23:02:40 bdeegan"
|
| +
|
| +import getopt
|
| +import glob
|
| +import os
|
| +import re
|
| +import shutil
|
| +import sys
|
| +import tempfile
|
| +import time
|
| +
|
| +try:
|
| + sorted
|
| +except NameError:
|
| + # Pre-2.4 Python has no sorted() function.
|
| + #
|
| + # The pre-2.4 Python list.sort() method does not support
|
| + # list.sort(key=) nor list.sort(reverse=) keyword arguments, so
|
| + # we must implement the functionality of those keyword arguments
|
| + # by hand instead of passing them to list.sort().
|
| + def sorted(iterable, cmp=None, key=None, reverse=False):
|
| + if key is not None:
|
| + result = [(key(x), x) for x in iterable]
|
| + else:
|
| + result = iterable[:]
|
| + if cmp is None:
|
| + # Pre-2.3 Python does not support list.sort(None).
|
| + result.sort()
|
| + else:
|
| + result.sort(cmp)
|
| + if key is not None:
|
| + result = [t1 for t0,t1 in result]
|
| + if reverse:
|
| + result.reverse()
|
| + return result
|
| +
|
| +if os.environ.get('SCONS_HORRIBLE_REGRESSION_TEST_HACK') is not None:
|
| + # We can't apply the 'callable' fixer until the floor is 2.6, but the
|
| + # '-3' option to Python 2.6 and 2.7 generates almost ten thousand
|
| + # warnings. This hack allows us to run regression tests with the '-3'
|
| + # option by replacing the callable() built-in function with a hack
|
| + # that performs the same function but doesn't generate the warning.
|
| + # Note that this hack is ONLY intended to be used for regression
|
| + # testing, and should NEVER be used for real runs.
|
| + from types import ClassType
|
| + def callable(obj):
|
| + if hasattr(obj, '__call__'): return True
|
| + if isinstance(obj, (ClassType, type)): return True
|
| + return False
|
| +
|
| +def make_temp_file(**kw):
|
| + try:
|
| + result = tempfile.mktemp(**kw)
|
| + try:
|
| + result = os.path.realpath(result)
|
| + except AttributeError:
|
| + # Python 2.1 has no os.path.realpath() method.
|
| + pass
|
| + except TypeError:
|
| + try:
|
| + save_template = tempfile.template
|
| + prefix = kw['prefix']
|
| + del kw['prefix']
|
| + tempfile.template = prefix
|
| + result = tempfile.mktemp(**kw)
|
| + finally:
|
| + tempfile.template = save_template
|
| + return result
|
| +
|
| +def HACK_for_exec(cmd, *args):
|
| + '''
|
| + For some reason, Python won't allow an exec() within a function
|
| + that also declares an internal function (including lambda functions).
|
| + This function is a hack that calls exec() in a function with no
|
| + internal functions.
|
| + '''
|
| + if not args: exec(cmd)
|
| + elif len(args) == 1: exec cmd in args[0]
|
| + else: exec cmd in args[0], args[1]
|
| +
|
| +class Plotter(object):
|
| + def increment_size(self, largest):
|
| + """
|
| + Return the size of each horizontal increment line for a specified
|
| + maximum value. This returns a value that will provide somewhere
|
| + between 5 and 9 horizontal lines on the graph, on some set of
|
| + boundaries that are multiples of 10/100/1000/etc.
|
| + """
|
| + i = largest // 5
|
| + if not i:
|
| + return largest
|
| + multiplier = 1
|
| + while i >= 10:
|
| + i = i // 10
|
| + multiplier = multiplier * 10
|
| + return i * multiplier
|
| +
|
| + def max_graph_value(self, largest):
|
| + # Round up to next integer.
|
| + largest = int(largest) + 1
|
| + increment = self.increment_size(largest)
|
| + return ((largest + increment - 1) // increment) * increment
|
| +
|
| +class Line(object):
|
| + def __init__(self, points, type, title, label, comment, fmt="%s %s"):
|
| + self.points = points
|
| + self.type = type
|
| + self.title = title
|
| + self.label = label
|
| + self.comment = comment
|
| + self.fmt = fmt
|
| +
|
| + def print_label(self, inx, x, y):
|
| + if self.label:
|
| + print 'set label %s "%s" at %s,%s right' % (inx, self.label, x, y)
|
| +
|
| + def plot_string(self):
|
| + if self.title:
|
| + title_string = 'title "%s"' % self.title
|
| + else:
|
| + title_string = 'notitle'
|
| + return "'-' %s with lines lt %s" % (title_string, self.type)
|
| +
|
| + def print_points(self, fmt=None):
|
| + if fmt is None:
|
| + fmt = self.fmt
|
| + if self.comment:
|
| + print '# %s' % self.comment
|
| + for x, y in self.points:
|
| + # If y is None, it usually represents some kind of break
|
| + # in the line's index number. We might want to represent
|
| + # this some way rather than just drawing the line straight
|
| + # between the two points on either side.
|
| + if not y is None:
|
| + print fmt % (x, y)
|
| + print 'e'
|
| +
|
| + def get_x_values(self):
|
| + return [ p[0] for p in self.points ]
|
| +
|
| + def get_y_values(self):
|
| + return [ p[1] for p in self.points ]
|
| +
|
| +class Gnuplotter(Plotter):
|
| +
|
| + def __init__(self, title, key_location):
|
| + self.lines = []
|
| + self.title = title
|
| + self.key_location = key_location
|
| +
|
| + def line(self, points, type, title=None, label=None, comment=None, fmt='%s %s'):
|
| + if points:
|
| + line = Line(points, type, title, label, comment, fmt)
|
| + self.lines.append(line)
|
| +
|
| + def plot_string(self, line):
|
| + return line.plot_string()
|
| +
|
| + def vertical_bar(self, x, type, label, comment):
|
| + if self.get_min_x() <= x and x <= self.get_max_x():
|
| + points = [(x, 0), (x, self.max_graph_value(self.get_max_y()))]
|
| + self.line(points, type, label, comment)
|
| +
|
| + def get_all_x_values(self):
|
| + result = []
|
| + for line in self.lines:
|
| + result.extend(line.get_x_values())
|
| + return [r for r in result if not r is None]
|
| +
|
| + def get_all_y_values(self):
|
| + result = []
|
| + for line in self.lines:
|
| + result.extend(line.get_y_values())
|
| + return [r for r in result if not r is None]
|
| +
|
| + def get_min_x(self):
|
| + try:
|
| + return self.min_x
|
| + except AttributeError:
|
| + try:
|
| + self.min_x = min(self.get_all_x_values())
|
| + except ValueError:
|
| + self.min_x = 0
|
| + return self.min_x
|
| +
|
| + def get_max_x(self):
|
| + try:
|
| + return self.max_x
|
| + except AttributeError:
|
| + try:
|
| + self.max_x = max(self.get_all_x_values())
|
| + except ValueError:
|
| + self.max_x = 0
|
| + return self.max_x
|
| +
|
| + def get_min_y(self):
|
| + try:
|
| + return self.min_y
|
| + except AttributeError:
|
| + try:
|
| + self.min_y = min(self.get_all_y_values())
|
| + except ValueError:
|
| + self.min_y = 0
|
| + return self.min_y
|
| +
|
| + def get_max_y(self):
|
| + try:
|
| + return self.max_y
|
| + except AttributeError:
|
| + try:
|
| + self.max_y = max(self.get_all_y_values())
|
| + except ValueError:
|
| + self.max_y = 0
|
| + return self.max_y
|
| +
|
| + def draw(self):
|
| +
|
| + if not self.lines:
|
| + return
|
| +
|
| + if self.title:
|
| + print 'set title "%s"' % self.title
|
| + print 'set key %s' % self.key_location
|
| +
|
| + min_y = self.get_min_y()
|
| + max_y = self.max_graph_value(self.get_max_y())
|
| + incr = (max_y - min_y) / 10.0
|
| + start = min_y + (max_y / 2.0) + (2.0 * incr)
|
| + position = [ start - (i * incr) for i in range(5) ]
|
| +
|
| + inx = 1
|
| + for line in self.lines:
|
| + line.print_label(inx, line.points[0][0]-1,
|
| + position[(inx-1) % len(position)])
|
| + inx += 1
|
| +
|
| + plot_strings = [ self.plot_string(l) for l in self.lines ]
|
| + print 'plot ' + ', \\\n '.join(plot_strings)
|
| +
|
| + for line in self.lines:
|
| + line.print_points()
|
| +
|
| +
|
| +
|
| +def untar(fname):
|
| + import tarfile
|
| + tar = tarfile.open(name=fname, mode='r')
|
| + for tarinfo in tar:
|
| + tar.extract(tarinfo)
|
| + tar.close()
|
| +
|
| +def unzip(fname):
|
| + import zipfile
|
| + zf = zipfile.ZipFile(fname, 'r')
|
| + for name in zf.namelist():
|
| + dir = os.path.dirname(name)
|
| + try:
|
| + os.makedirs(dir)
|
| + except:
|
| + pass
|
| + open(name, 'w').write(zf.read(name))
|
| +
|
| +def read_tree(dir):
|
| + for dirpath, dirnames, filenames in os.walk(dir):
|
| + for fn in filenames:
|
| + fn = os.path.join(dirpath, fn)
|
| + if os.path.isfile(fn):
|
| + open(fn, 'rb').read()
|
| +
|
| +def redirect_to_file(command, log):
|
| + return '%s > %s 2>&1' % (command, log)
|
| +
|
| +def tee_to_file(command, log):
|
| + return '%s 2>&1 | tee %s' % (command, log)
|
| +
|
| +
|
| +
|
| +class SConsTimer(object):
|
| + """
|
| + Usage: scons-time SUBCOMMAND [ARGUMENTS]
|
| + Type "scons-time help SUBCOMMAND" for help on a specific subcommand.
|
| +
|
| + Available subcommands:
|
| + func Extract test-run data for a function
|
| + help Provides help
|
| + mem Extract --debug=memory data from test runs
|
| + obj Extract --debug=count data from test runs
|
| + time Extract --debug=time data from test runs
|
| + run Runs a test configuration
|
| + """
|
| +
|
| + name = 'scons-time'
|
| + name_spaces = ' '*len(name)
|
| +
|
| + def makedict(**kw):
|
| + return kw
|
| +
|
| + default_settings = makedict(
|
| + aegis = 'aegis',
|
| + aegis_project = None,
|
| + chdir = None,
|
| + config_file = None,
|
| + initial_commands = [],
|
| + key_location = 'bottom left',
|
| + orig_cwd = os.getcwd(),
|
| + outdir = None,
|
| + prefix = '',
|
| + python = '"%s"' % sys.executable,
|
| + redirect = redirect_to_file,
|
| + scons = None,
|
| + scons_flags = '--debug=count --debug=memory --debug=time --debug=memoizer',
|
| + scons_lib_dir = None,
|
| + scons_wrapper = None,
|
| + startup_targets = '--help',
|
| + subdir = None,
|
| + subversion_url = None,
|
| + svn = 'svn',
|
| + svn_co_flag = '-q',
|
| + tar = 'tar',
|
| + targets = '',
|
| + targets0 = None,
|
| + targets1 = None,
|
| + targets2 = None,
|
| + title = None,
|
| + unzip = 'unzip',
|
| + verbose = False,
|
| + vertical_bars = [],
|
| +
|
| + unpack_map = {
|
| + '.tar.gz' : (untar, '%(tar)s xzf %%s'),
|
| + '.tgz' : (untar, '%(tar)s xzf %%s'),
|
| + '.tar' : (untar, '%(tar)s xf %%s'),
|
| + '.zip' : (unzip, '%(unzip)s %%s'),
|
| + },
|
| + )
|
| +
|
| + run_titles = [
|
| + 'Startup',
|
| + 'Full build',
|
| + 'Up-to-date build',
|
| + ]
|
| +
|
| + run_commands = [
|
| + '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof0)s %(targets0)s',
|
| + '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof1)s %(targets1)s',
|
| + '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof2)s %(targets2)s',
|
| + ]
|
| +
|
| + stages = [
|
| + 'pre-read',
|
| + 'post-read',
|
| + 'pre-build',
|
| + 'post-build',
|
| + ]
|
| +
|
| + stage_strings = {
|
| + 'pre-read' : 'Memory before reading SConscript files:',
|
| + 'post-read' : 'Memory after reading SConscript files:',
|
| + 'pre-build' : 'Memory before building targets:',
|
| + 'post-build' : 'Memory after building targets:',
|
| + }
|
| +
|
| + memory_string_all = 'Memory '
|
| +
|
| + default_stage = stages[-1]
|
| +
|
| + time_strings = {
|
| + 'total' : 'Total build time',
|
| + 'SConscripts' : 'Total SConscript file execution time',
|
| + 'SCons' : 'Total SCons execution time',
|
| + 'commands' : 'Total command execution time',
|
| + }
|
| +
|
| + time_string_all = 'Total .* time'
|
| +
|
| + #
|
| +
|
| + def __init__(self):
|
| + self.__dict__.update(self.default_settings)
|
| +
|
| + # Functions for displaying and executing commands.
|
| +
|
| + def subst(self, x, dictionary):
|
| + try:
|
| + return x % dictionary
|
| + except TypeError:
|
| + # x isn't a string (it's probably a Python function),
|
| + # so just return it.
|
| + return x
|
| +
|
| + def subst_variables(self, command, dictionary):
|
| + """
|
| + Substitutes (via the format operator) the values in the specified
|
| + dictionary into the specified command.
|
| +
|
| + The command can be an (action, string) tuple. In all cases, we
|
| + perform substitution on strings and don't worry if something isn't
|
| + a string. (It's probably a Python function to be executed.)
|
| + """
|
| + try:
|
| + command + ''
|
| + except TypeError:
|
| + action = command[0]
|
| + string = command[1]
|
| + args = command[2:]
|
| + else:
|
| + action = command
|
| + string = action
|
| + args = (())
|
| + action = self.subst(action, dictionary)
|
| + string = self.subst(string, dictionary)
|
| + return (action, string, args)
|
| +
|
| + def _do_not_display(self, msg, *args):
|
| + pass
|
| +
|
| + def display(self, msg, *args):
|
| + """
|
| + Displays the specified message.
|
| +
|
| + Each message is prepended with a standard prefix of our name
|
| + plus the time.
|
| + """
|
| + if callable(msg):
|
| + msg = msg(*args)
|
| + else:
|
| + msg = msg % args
|
| + if msg is None:
|
| + return
|
| + fmt = '%s[%s]: %s\n'
|
| + sys.stdout.write(fmt % (self.name, time.strftime('%H:%M:%S'), msg))
|
| +
|
| + def _do_not_execute(self, action, *args):
|
| + pass
|
| +
|
| + def execute(self, action, *args):
|
| + """
|
| + Executes the specified action.
|
| +
|
| + The action is called if it's a callable Python function, and
|
| + otherwise passed to os.system().
|
| + """
|
| + if callable(action):
|
| + action(*args)
|
| + else:
|
| + os.system(action % args)
|
| +
|
| + def run_command_list(self, commands, dict):
|
| + """
|
| + Executes a list of commands, substituting values from the
|
| + specified dictionary.
|
| + """
|
| + commands = [ self.subst_variables(c, dict) for c in commands ]
|
| + for action, string, args in commands:
|
| + self.display(string, *args)
|
| + sys.stdout.flush()
|
| + status = self.execute(action, *args)
|
| + if status:
|
| + sys.exit(status)
|
| +
|
| + def log_display(self, command, log):
|
| + command = self.subst(command, self.__dict__)
|
| + if log:
|
| + command = self.redirect(command, log)
|
| + return command
|
| +
|
| + def log_execute(self, command, log):
|
| + command = self.subst(command, self.__dict__)
|
| + output = os.popen(command).read()
|
| + if self.verbose:
|
| + sys.stdout.write(output)
|
| + open(log, 'wb').write(output)
|
| +
|
| + #
|
| +
|
| + def archive_splitext(self, path):
|
| + """
|
| + Splits an archive name into a filename base and extension.
|
| +
|
| + This is like os.path.splitext() (which it calls) except that it
|
| + also looks for '.tar.gz' and treats it as an atomic extensions.
|
| + """
|
| + if path.endswith('.tar.gz'):
|
| + return path[:-7], path[-7:]
|
| + else:
|
| + return os.path.splitext(path)
|
| +
|
| + def args_to_files(self, args, tail=None):
|
| + """
|
| + Takes a list of arguments, expands any glob patterns, and
|
| + returns the last "tail" files from the list.
|
| + """
|
| + files = []
|
| + for a in args:
|
| + files.extend(sorted(glob.glob(a)))
|
| +
|
| + if tail:
|
| + files = files[-tail:]
|
| +
|
| + return files
|
| +
|
| + def ascii_table(self, files, columns,
|
| + line_function, file_function=lambda x: x,
|
| + *args, **kw):
|
| +
|
| + header_fmt = ' '.join(['%12s'] * len(columns))
|
| + line_fmt = header_fmt + ' %s'
|
| +
|
| + print header_fmt % columns
|
| +
|
| + for file in files:
|
| + t = line_function(file, *args, **kw)
|
| + if t is None:
|
| + t = []
|
| + diff = len(columns) - len(t)
|
| + if diff > 0:
|
| + t += [''] * diff
|
| + t.append(file_function(file))
|
| + print line_fmt % tuple(t)
|
| +
|
| + def collect_results(self, files, function, *args, **kw):
|
| + results = {}
|
| +
|
| + for file in files:
|
| + base = os.path.splitext(file)[0]
|
| + run, index = base.split('-')[-2:]
|
| +
|
| + run = int(run)
|
| + index = int(index)
|
| +
|
| + value = function(file, *args, **kw)
|
| +
|
| + try:
|
| + r = results[index]
|
| + except KeyError:
|
| + r = []
|
| + results[index] = r
|
| + r.append((run, value))
|
| +
|
| + return results
|
| +
|
| + def doc_to_help(self, obj):
|
| + """
|
| + Translates an object's __doc__ string into help text.
|
| +
|
| + This strips a consistent number of spaces from each line in the
|
| + help text, essentially "outdenting" the text to the left-most
|
| + column.
|
| + """
|
| + doc = obj.__doc__
|
| + if doc is None:
|
| + return ''
|
| + return self.outdent(doc)
|
| +
|
| + def find_next_run_number(self, dir, prefix):
|
| + """
|
| + Returns the next run number in a directory for the specified prefix.
|
| +
|
| + Examines the contents the specified directory for files with the
|
| + specified prefix, extracts the run numbers from each file name,
|
| + and returns the next run number after the largest it finds.
|
| + """
|
| + x = re.compile(re.escape(prefix) + '-([0-9]+).*')
|
| + matches = [x.match(e) for e in os.listdir(dir)]
|
| + matches = [_f for _f in matches if _f]
|
| + if not matches:
|
| + return 0
|
| + run_numbers = [int(m.group(1)) for m in matches]
|
| + return int(max(run_numbers)) + 1
|
| +
|
| + def gnuplot_results(self, results, fmt='%s %.3f'):
|
| + """
|
| + Prints out a set of results in Gnuplot format.
|
| + """
|
| + gp = Gnuplotter(self.title, self.key_location)
|
| +
|
| + for i in sorted(results.keys()):
|
| + try:
|
| + t = self.run_titles[i]
|
| + except IndexError:
|
| + t = '??? %s ???' % i
|
| + results[i].sort()
|
| + gp.line(results[i], i+1, t, None, t, fmt=fmt)
|
| +
|
| + for bar_tuple in self.vertical_bars:
|
| + try:
|
| + x, type, label, comment = bar_tuple
|
| + except ValueError:
|
| + x, type, label = bar_tuple
|
| + comment = label
|
| + gp.vertical_bar(x, type, label, comment)
|
| +
|
| + gp.draw()
|
| +
|
| + def logfile_name(self, invocation):
|
| + """
|
| + Returns the absolute path of a log file for the specificed
|
| + invocation number.
|
| + """
|
| + name = self.prefix_run + '-%d.log' % invocation
|
| + return os.path.join(self.outdir, name)
|
| +
|
| + def outdent(self, s):
|
| + """
|
| + Strip as many spaces from each line as are found at the beginning
|
| + of the first line in the list.
|
| + """
|
| + lines = s.split('\n')
|
| + if lines[0] == '':
|
| + lines = lines[1:]
|
| + spaces = re.match(' *', lines[0]).group(0)
|
| + def strip_initial_spaces(l, s=spaces):
|
| + if l.startswith(spaces):
|
| + l = l[len(spaces):]
|
| + return l
|
| + return '\n'.join([ strip_initial_spaces(l) for l in lines ]) + '\n'
|
| +
|
| + def profile_name(self, invocation):
|
| + """
|
| + Returns the absolute path of a profile file for the specified
|
| + invocation number.
|
| + """
|
| + name = self.prefix_run + '-%d.prof' % invocation
|
| + return os.path.join(self.outdir, name)
|
| +
|
| + def set_env(self, key, value):
|
| + os.environ[key] = value
|
| +
|
| + #
|
| +
|
| + def get_debug_times(self, file, time_string=None):
|
| + """
|
| + Fetch times from the --debug=time strings in the specified file.
|
| + """
|
| + if time_string is None:
|
| + search_string = self.time_string_all
|
| + else:
|
| + search_string = time_string
|
| + contents = open(file).read()
|
| + if not contents:
|
| + sys.stderr.write('file %s has no contents!\n' % repr(file))
|
| + return None
|
| + result = re.findall(r'%s: ([\d\.]*)' % search_string, contents)[-4:]
|
| + result = [ float(r) for r in result ]
|
| + if not time_string is None:
|
| + try:
|
| + result = result[0]
|
| + except IndexError:
|
| + sys.stderr.write('file %s has no results!\n' % repr(file))
|
| + return None
|
| + return result
|
| +
|
| + def get_function_profile(self, file, function):
|
| + """
|
| + Returns the file, line number, function name, and cumulative time.
|
| + """
|
| + try:
|
| + import pstats
|
| + except ImportError, e:
|
| + sys.stderr.write('%s: func: %s\n' % (self.name, e))
|
| + sys.stderr.write('%s This version of Python is missing the profiler.\n' % self.name_spaces)
|
| + sys.stderr.write('%s Cannot use the "func" subcommand.\n' % self.name_spaces)
|
| + sys.exit(1)
|
| + statistics = pstats.Stats(file).stats
|
| + matches = [ e for e in statistics.items() if e[0][2] == function ]
|
| + r = matches[0]
|
| + return r[0][0], r[0][1], r[0][2], r[1][3]
|
| +
|
| + def get_function_time(self, file, function):
|
| + """
|
| + Returns just the cumulative time for the specified function.
|
| + """
|
| + return self.get_function_profile(file, function)[3]
|
| +
|
| + def get_memory(self, file, memory_string=None):
|
| + """
|
| + Returns a list of integers of the amount of memory used. The
|
| + default behavior is to return all the stages.
|
| + """
|
| + if memory_string is None:
|
| + search_string = self.memory_string_all
|
| + else:
|
| + search_string = memory_string
|
| + lines = open(file).readlines()
|
| + lines = [ l for l in lines if l.startswith(search_string) ][-4:]
|
| + result = [ int(l.split()[-1]) for l in lines[-4:] ]
|
| + if len(result) == 1:
|
| + result = result[0]
|
| + return result
|
| +
|
| + def get_object_counts(self, file, object_name, index=None):
|
| + """
|
| + Returns the counts of the specified object_name.
|
| + """
|
| + object_string = ' ' + object_name + '\n'
|
| + lines = open(file).readlines()
|
| + line = [ l for l in lines if l.endswith(object_string) ][0]
|
| + result = [ int(field) for field in line.split()[:4] ]
|
| + if index is not None:
|
| + result = result[index]
|
| + return result
|
| +
|
| + #
|
| +
|
| + command_alias = {}
|
| +
|
| + def execute_subcommand(self, argv):
|
| + """
|
| + Executes the do_*() function for the specified subcommand (argv[0]).
|
| + """
|
| + if not argv:
|
| + return
|
| + cmdName = self.command_alias.get(argv[0], argv[0])
|
| + try:
|
| + func = getattr(self, 'do_' + cmdName)
|
| + except AttributeError:
|
| + return self.default(argv)
|
| + try:
|
| + return func(argv)
|
| + except TypeError, e:
|
| + sys.stderr.write("%s %s: %s\n" % (self.name, cmdName, e))
|
| + import traceback
|
| + traceback.print_exc(file=sys.stderr)
|
| + sys.stderr.write("Try '%s help %s'\n" % (self.name, cmdName))
|
| +
|
| + def default(self, argv):
|
| + """
|
| + The default behavior for an unknown subcommand. Prints an
|
| + error message and exits.
|
| + """
|
| + sys.stderr.write('%s: Unknown subcommand "%s".\n' % (self.name, argv[0]))
|
| + sys.stderr.write('Type "%s help" for usage.\n' % self.name)
|
| + sys.exit(1)
|
| +
|
| + #
|
| +
|
| + def do_help(self, argv):
|
| + """
|
| + """
|
| + if argv[1:]:
|
| + for arg in argv[1:]:
|
| + try:
|
| + func = getattr(self, 'do_' + arg)
|
| + except AttributeError:
|
| + sys.stderr.write('%s: No help for "%s"\n' % (self.name, arg))
|
| + else:
|
| + try:
|
| + help = getattr(self, 'help_' + arg)
|
| + except AttributeError:
|
| + sys.stdout.write(self.doc_to_help(func))
|
| + sys.stdout.flush()
|
| + else:
|
| + help()
|
| + else:
|
| + doc = self.doc_to_help(self.__class__)
|
| + if doc:
|
| + sys.stdout.write(doc)
|
| + sys.stdout.flush()
|
| + return None
|
| +
|
| + #
|
| +
|
| + def help_func(self):
|
| + help = """\
|
| + Usage: scons-time func [OPTIONS] FILE [...]
|
| +
|
| + -C DIR, --chdir=DIR Change to DIR before looking for files
|
| + -f FILE, --file=FILE Read configuration from specified FILE
|
| + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
|
| + --func=NAME, --function=NAME Report time for function NAME
|
| + -h, --help Print this help and exit
|
| + -p STRING, --prefix=STRING Use STRING as log file/profile prefix
|
| + -t NUMBER, --tail=NUMBER Only report the last NUMBER files
|
| + --title=TITLE Specify the output plot TITLE
|
| + """
|
| + sys.stdout.write(self.outdent(help))
|
| + sys.stdout.flush()
|
| +
|
| + def do_func(self, argv):
|
| + """
|
| + """
|
| + format = 'ascii'
|
| + function_name = '_main'
|
| + tail = None
|
| +
|
| + short_opts = '?C:f:hp:t:'
|
| +
|
| + long_opts = [
|
| + 'chdir=',
|
| + 'file=',
|
| + 'fmt=',
|
| + 'format=',
|
| + 'func=',
|
| + 'function=',
|
| + 'help',
|
| + 'prefix=',
|
| + 'tail=',
|
| + 'title=',
|
| + ]
|
| +
|
| + opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
|
| +
|
| + for o, a in opts:
|
| + if o in ('-C', '--chdir'):
|
| + self.chdir = a
|
| + elif o in ('-f', '--file'):
|
| + self.config_file = a
|
| + elif o in ('--fmt', '--format'):
|
| + format = a
|
| + elif o in ('--func', '--function'):
|
| + function_name = a
|
| + elif o in ('-?', '-h', '--help'):
|
| + self.do_help(['help', 'func'])
|
| + sys.exit(0)
|
| + elif o in ('--max',):
|
| + max_time = int(a)
|
| + elif o in ('-p', '--prefix'):
|
| + self.prefix = a
|
| + elif o in ('-t', '--tail'):
|
| + tail = int(a)
|
| + elif o in ('--title',):
|
| + self.title = a
|
| +
|
| + if self.config_file:
|
| + exec open(self.config_file, 'rU').read() in self.__dict__
|
| +
|
| + if self.chdir:
|
| + os.chdir(self.chdir)
|
| +
|
| + if not args:
|
| +
|
| + pattern = '%s*.prof' % self.prefix
|
| + args = self.args_to_files([pattern], tail)
|
| +
|
| + if not args:
|
| + if self.chdir:
|
| + directory = self.chdir
|
| + else:
|
| + directory = os.getcwd()
|
| +
|
| + sys.stderr.write('%s: func: No arguments specified.\n' % self.name)
|
| + sys.stderr.write('%s No %s*.prof files found in "%s".\n' % (self.name_spaces, self.prefix, directory))
|
| + sys.stderr.write('%s Type "%s help func" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| +
|
| + else:
|
| +
|
| + args = self.args_to_files(args, tail)
|
| +
|
| + cwd_ = os.getcwd() + os.sep
|
| +
|
| + if format == 'ascii':
|
| +
|
| + for file in args:
|
| + try:
|
| + f, line, func, time = \
|
| + self.get_function_profile(file, function_name)
|
| + except ValueError, e:
|
| + sys.stderr.write("%s: func: %s: %s\n" %
|
| + (self.name, file, e))
|
| + else:
|
| + if f.startswith(cwd_):
|
| + f = f[len(cwd_):]
|
| + print "%.3f %s:%d(%s)" % (time, f, line, func)
|
| +
|
| + elif format == 'gnuplot':
|
| +
|
| + results = self.collect_results(args, self.get_function_time,
|
| + function_name)
|
| +
|
| + self.gnuplot_results(results)
|
| +
|
| + else:
|
| +
|
| + sys.stderr.write('%s: func: Unknown format "%s".\n' % (self.name, format))
|
| + sys.exit(1)
|
| +
|
| + #
|
| +
|
| + def help_mem(self):
|
| + help = """\
|
| + Usage: scons-time mem [OPTIONS] FILE [...]
|
| +
|
| + -C DIR, --chdir=DIR Change to DIR before looking for files
|
| + -f FILE, --file=FILE Read configuration from specified FILE
|
| + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
|
| + -h, --help Print this help and exit
|
| + -p STRING, --prefix=STRING Use STRING as log file/profile prefix
|
| + --stage=STAGE Plot memory at the specified stage:
|
| + pre-read, post-read, pre-build,
|
| + post-build (default: post-build)
|
| + -t NUMBER, --tail=NUMBER Only report the last NUMBER files
|
| + --title=TITLE Specify the output plot TITLE
|
| + """
|
| + sys.stdout.write(self.outdent(help))
|
| + sys.stdout.flush()
|
| +
|
| + def do_mem(self, argv):
|
| +
|
| + format = 'ascii'
|
| + logfile_path = lambda x: x
|
| + stage = self.default_stage
|
| + tail = None
|
| +
|
| + short_opts = '?C:f:hp:t:'
|
| +
|
| + long_opts = [
|
| + 'chdir=',
|
| + 'file=',
|
| + 'fmt=',
|
| + 'format=',
|
| + 'help',
|
| + 'prefix=',
|
| + 'stage=',
|
| + 'tail=',
|
| + 'title=',
|
| + ]
|
| +
|
| + opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
|
| +
|
| + for o, a in opts:
|
| + if o in ('-C', '--chdir'):
|
| + self.chdir = a
|
| + elif o in ('-f', '--file'):
|
| + self.config_file = a
|
| + elif o in ('--fmt', '--format'):
|
| + format = a
|
| + elif o in ('-?', '-h', '--help'):
|
| + self.do_help(['help', 'mem'])
|
| + sys.exit(0)
|
| + elif o in ('-p', '--prefix'):
|
| + self.prefix = a
|
| + elif o in ('--stage',):
|
| + if not a in self.stages:
|
| + sys.stderr.write('%s: mem: Unrecognized stage "%s".\n' % (self.name, a))
|
| + sys.exit(1)
|
| + stage = a
|
| + elif o in ('-t', '--tail'):
|
| + tail = int(a)
|
| + elif o in ('--title',):
|
| + self.title = a
|
| +
|
| + if self.config_file:
|
| + HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__)
|
| +
|
| + if self.chdir:
|
| + os.chdir(self.chdir)
|
| + logfile_path = lambda x: os.path.join(self.chdir, x)
|
| +
|
| + if not args:
|
| +
|
| + pattern = '%s*.log' % self.prefix
|
| + args = self.args_to_files([pattern], tail)
|
| +
|
| + if not args:
|
| + if self.chdir:
|
| + directory = self.chdir
|
| + else:
|
| + directory = os.getcwd()
|
| +
|
| + sys.stderr.write('%s: mem: No arguments specified.\n' % self.name)
|
| + sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory))
|
| + sys.stderr.write('%s Type "%s help mem" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| +
|
| + else:
|
| +
|
| + args = self.args_to_files(args, tail)
|
| +
|
| + cwd_ = os.getcwd() + os.sep
|
| +
|
| + if format == 'ascii':
|
| +
|
| + self.ascii_table(args, tuple(self.stages), self.get_memory, logfile_path)
|
| +
|
| + elif format == 'gnuplot':
|
| +
|
| + results = self.collect_results(args, self.get_memory,
|
| + self.stage_strings[stage])
|
| +
|
| + self.gnuplot_results(results)
|
| +
|
| + else:
|
| +
|
| + sys.stderr.write('%s: mem: Unknown format "%s".\n' % (self.name, format))
|
| + sys.exit(1)
|
| +
|
| + return 0
|
| +
|
| + #
|
| +
|
| + def help_obj(self):
|
| + help = """\
|
| + Usage: scons-time obj [OPTIONS] OBJECT FILE [...]
|
| +
|
| + -C DIR, --chdir=DIR Change to DIR before looking for files
|
| + -f FILE, --file=FILE Read configuration from specified FILE
|
| + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
|
| + -h, --help Print this help and exit
|
| + -p STRING, --prefix=STRING Use STRING as log file/profile prefix
|
| + --stage=STAGE Plot memory at the specified stage:
|
| + pre-read, post-read, pre-build,
|
| + post-build (default: post-build)
|
| + -t NUMBER, --tail=NUMBER Only report the last NUMBER files
|
| + --title=TITLE Specify the output plot TITLE
|
| + """
|
| + sys.stdout.write(self.outdent(help))
|
| + sys.stdout.flush()
|
| +
|
| + def do_obj(self, argv):
|
| +
|
| + format = 'ascii'
|
| + logfile_path = lambda x: x
|
| + stage = self.default_stage
|
| + tail = None
|
| +
|
| + short_opts = '?C:f:hp:t:'
|
| +
|
| + long_opts = [
|
| + 'chdir=',
|
| + 'file=',
|
| + 'fmt=',
|
| + 'format=',
|
| + 'help',
|
| + 'prefix=',
|
| + 'stage=',
|
| + 'tail=',
|
| + 'title=',
|
| + ]
|
| +
|
| + opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
|
| +
|
| + for o, a in opts:
|
| + if o in ('-C', '--chdir'):
|
| + self.chdir = a
|
| + elif o in ('-f', '--file'):
|
| + self.config_file = a
|
| + elif o in ('--fmt', '--format'):
|
| + format = a
|
| + elif o in ('-?', '-h', '--help'):
|
| + self.do_help(['help', 'obj'])
|
| + sys.exit(0)
|
| + elif o in ('-p', '--prefix'):
|
| + self.prefix = a
|
| + elif o in ('--stage',):
|
| + if not a in self.stages:
|
| + sys.stderr.write('%s: obj: Unrecognized stage "%s".\n' % (self.name, a))
|
| + sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| + stage = a
|
| + elif o in ('-t', '--tail'):
|
| + tail = int(a)
|
| + elif o in ('--title',):
|
| + self.title = a
|
| +
|
| + if not args:
|
| + sys.stderr.write('%s: obj: Must specify an object name.\n' % self.name)
|
| + sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| +
|
| + object_name = args.pop(0)
|
| +
|
| + if self.config_file:
|
| + HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__)
|
| +
|
| + if self.chdir:
|
| + os.chdir(self.chdir)
|
| + logfile_path = lambda x: os.path.join(self.chdir, x)
|
| +
|
| + if not args:
|
| +
|
| + pattern = '%s*.log' % self.prefix
|
| + args = self.args_to_files([pattern], tail)
|
| +
|
| + if not args:
|
| + if self.chdir:
|
| + directory = self.chdir
|
| + else:
|
| + directory = os.getcwd()
|
| +
|
| + sys.stderr.write('%s: obj: No arguments specified.\n' % self.name)
|
| + sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory))
|
| + sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| +
|
| + else:
|
| +
|
| + args = self.args_to_files(args, tail)
|
| +
|
| + cwd_ = os.getcwd() + os.sep
|
| +
|
| + if format == 'ascii':
|
| +
|
| + self.ascii_table(args, tuple(self.stages), self.get_object_counts, logfile_path, object_name)
|
| +
|
| + elif format == 'gnuplot':
|
| +
|
| + stage_index = 0
|
| + for s in self.stages:
|
| + if stage == s:
|
| + break
|
| + stage_index = stage_index + 1
|
| +
|
| + results = self.collect_results(args, self.get_object_counts,
|
| + object_name, stage_index)
|
| +
|
| + self.gnuplot_results(results)
|
| +
|
| + else:
|
| +
|
| + sys.stderr.write('%s: obj: Unknown format "%s".\n' % (self.name, format))
|
| + sys.exit(1)
|
| +
|
| + return 0
|
| +
|
| + #
|
| +
|
| + def help_run(self):
|
| + help = """\
|
| + Usage: scons-time run [OPTIONS] [FILE ...]
|
| +
|
| + --aegis=PROJECT Use SCons from the Aegis PROJECT
|
| + --chdir=DIR Name of unpacked directory for chdir
|
| + -f FILE, --file=FILE Read configuration from specified FILE
|
| + -h, --help Print this help and exit
|
| + -n, --no-exec No execute, just print command lines
|
| + --number=NUMBER Put output in files for run NUMBER
|
| + --outdir=OUTDIR Put output files in OUTDIR
|
| + -p STRING, --prefix=STRING Use STRING as log file/profile prefix
|
| + --python=PYTHON Time using the specified PYTHON
|
| + -q, --quiet Don't print command lines
|
| + --scons=SCONS Time using the specified SCONS
|
| + --svn=URL, --subversion=URL Use SCons from Subversion URL
|
| + -v, --verbose Display output of commands
|
| + """
|
| + sys.stdout.write(self.outdent(help))
|
| + sys.stdout.flush()
|
| +
|
| + def do_run(self, argv):
|
| + """
|
| + """
|
| + run_number_list = [None]
|
| +
|
| + short_opts = '?f:hnp:qs:v'
|
| +
|
| + long_opts = [
|
| + 'aegis=',
|
| + 'file=',
|
| + 'help',
|
| + 'no-exec',
|
| + 'number=',
|
| + 'outdir=',
|
| + 'prefix=',
|
| + 'python=',
|
| + 'quiet',
|
| + 'scons=',
|
| + 'svn=',
|
| + 'subdir=',
|
| + 'subversion=',
|
| + 'verbose',
|
| + ]
|
| +
|
| + opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
|
| +
|
| + for o, a in opts:
|
| + if o in ('--aegis',):
|
| + self.aegis_project = a
|
| + elif o in ('-f', '--file'):
|
| + self.config_file = a
|
| + elif o in ('-?', '-h', '--help'):
|
| + self.do_help(['help', 'run'])
|
| + sys.exit(0)
|
| + elif o in ('-n', '--no-exec'):
|
| + self.execute = self._do_not_execute
|
| + elif o in ('--number',):
|
| + run_number_list = self.split_run_numbers(a)
|
| + elif o in ('--outdir',):
|
| + self.outdir = a
|
| + elif o in ('-p', '--prefix'):
|
| + self.prefix = a
|
| + elif o in ('--python',):
|
| + self.python = a
|
| + elif o in ('-q', '--quiet'):
|
| + self.display = self._do_not_display
|
| + elif o in ('-s', '--subdir'):
|
| + self.subdir = a
|
| + elif o in ('--scons',):
|
| + self.scons = a
|
| + elif o in ('--svn', '--subversion'):
|
| + self.subversion_url = a
|
| + elif o in ('-v', '--verbose'):
|
| + self.redirect = tee_to_file
|
| + self.verbose = True
|
| + self.svn_co_flag = ''
|
| +
|
| + if not args and not self.config_file:
|
| + sys.stderr.write('%s: run: No arguments or -f config file specified.\n' % self.name)
|
| + sys.stderr.write('%s Type "%s help run" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| +
|
| + if self.config_file:
|
| + exec open(self.config_file, 'rU').read() in self.__dict__
|
| +
|
| + if args:
|
| + self.archive_list = args
|
| +
|
| + archive_file_name = os.path.split(self.archive_list[0])[1]
|
| +
|
| + if not self.subdir:
|
| + self.subdir = self.archive_splitext(archive_file_name)[0]
|
| +
|
| + if not self.prefix:
|
| + self.prefix = self.archive_splitext(archive_file_name)[0]
|
| +
|
| + prepare = None
|
| + if self.subversion_url:
|
| + prepare = self.prep_subversion_run
|
| + elif self.aegis_project:
|
| + prepare = self.prep_aegis_run
|
| +
|
| + for run_number in run_number_list:
|
| + self.individual_run(run_number, self.archive_list, prepare)
|
| +
|
| + def split_run_numbers(self, s):
|
| + result = []
|
| + for n in s.split(','):
|
| + try:
|
| + x, y = n.split('-')
|
| + except ValueError:
|
| + result.append(int(n))
|
| + else:
|
| + result.extend(list(range(int(x), int(y)+1)))
|
| + return result
|
| +
|
| + def scons_path(self, dir):
|
| + return os.path.join(dir, 'src', 'script', 'scons.py')
|
| +
|
| + def scons_lib_dir_path(self, dir):
|
| + return os.path.join(dir, 'src', 'engine')
|
| +
|
| + def prep_aegis_run(self, commands, removals):
|
| + self.aegis_tmpdir = make_temp_file(prefix = self.name + '-aegis-')
|
| + removals.append((shutil.rmtree, 'rm -rf %%s', self.aegis_tmpdir))
|
| +
|
| + self.aegis_parent_project = os.path.splitext(self.aegis_project)[0]
|
| + self.scons = self.scons_path(self.aegis_tmpdir)
|
| + self.scons_lib_dir = self.scons_lib_dir_path(self.aegis_tmpdir)
|
| +
|
| + commands.extend([
|
| + 'mkdir %(aegis_tmpdir)s',
|
| + (lambda: os.chdir(self.aegis_tmpdir), 'cd %(aegis_tmpdir)s'),
|
| + '%(aegis)s -cp -ind -p %(aegis_parent_project)s .',
|
| + '%(aegis)s -cp -ind -p %(aegis_project)s -delta %(run_number)s .',
|
| + ])
|
| +
|
| + def prep_subversion_run(self, commands, removals):
|
| + self.svn_tmpdir = make_temp_file(prefix = self.name + '-svn-')
|
| + removals.append((shutil.rmtree, 'rm -rf %%s', self.svn_tmpdir))
|
| +
|
| + self.scons = self.scons_path(self.svn_tmpdir)
|
| + self.scons_lib_dir = self.scons_lib_dir_path(self.svn_tmpdir)
|
| +
|
| + commands.extend([
|
| + 'mkdir %(svn_tmpdir)s',
|
| + '%(svn)s co %(svn_co_flag)s -r %(run_number)s %(subversion_url)s %(svn_tmpdir)s',
|
| + ])
|
| +
|
| + def individual_run(self, run_number, archive_list, prepare=None):
|
| + """
|
| + Performs an individual run of the default SCons invocations.
|
| + """
|
| +
|
| + commands = []
|
| + removals = []
|
| +
|
| + if prepare:
|
| + prepare(commands, removals)
|
| +
|
| + save_scons = self.scons
|
| + save_scons_wrapper = self.scons_wrapper
|
| + save_scons_lib_dir = self.scons_lib_dir
|
| +
|
| + if self.outdir is None:
|
| + self.outdir = self.orig_cwd
|
| + elif not os.path.isabs(self.outdir):
|
| + self.outdir = os.path.join(self.orig_cwd, self.outdir)
|
| +
|
| + if self.scons is None:
|
| + self.scons = self.scons_path(self.orig_cwd)
|
| +
|
| + if self.scons_lib_dir is None:
|
| + self.scons_lib_dir = self.scons_lib_dir_path(self.orig_cwd)
|
| +
|
| + if self.scons_wrapper is None:
|
| + self.scons_wrapper = self.scons
|
| +
|
| + if not run_number:
|
| + run_number = self.find_next_run_number(self.outdir, self.prefix)
|
| +
|
| + self.run_number = str(run_number)
|
| +
|
| + self.prefix_run = self.prefix + '-%03d' % run_number
|
| +
|
| + if self.targets0 is None:
|
| + self.targets0 = self.startup_targets
|
| + if self.targets1 is None:
|
| + self.targets1 = self.targets
|
| + if self.targets2 is None:
|
| + self.targets2 = self.targets
|
| +
|
| + self.tmpdir = make_temp_file(prefix = self.name + '-')
|
| +
|
| + commands.extend([
|
| + 'mkdir %(tmpdir)s',
|
| +
|
| + (os.chdir, 'cd %%s', self.tmpdir),
|
| + ])
|
| +
|
| + for archive in archive_list:
|
| + if not os.path.isabs(archive):
|
| + archive = os.path.join(self.orig_cwd, archive)
|
| + if os.path.isdir(archive):
|
| + dest = os.path.split(archive)[1]
|
| + commands.append((shutil.copytree, 'cp -r %%s %%s', archive, dest))
|
| + else:
|
| + suffix = self.archive_splitext(archive)[1]
|
| + unpack_command = self.unpack_map.get(suffix)
|
| + if not unpack_command:
|
| + dest = os.path.split(archive)[1]
|
| + commands.append((shutil.copyfile, 'cp %%s %%s', archive, dest))
|
| + else:
|
| + commands.append(unpack_command + (archive,))
|
| +
|
| + commands.extend([
|
| + (os.chdir, 'cd %%s', self.subdir),
|
| + ])
|
| +
|
| + commands.extend(self.initial_commands)
|
| +
|
| + commands.extend([
|
| + (lambda: read_tree('.'),
|
| + 'find * -type f | xargs cat > /dev/null'),
|
| +
|
| + (self.set_env, 'export %%s=%%s',
|
| + 'SCONS_LIB_DIR', self.scons_lib_dir),
|
| +
|
| + '%(python)s %(scons_wrapper)s --version',
|
| + ])
|
| +
|
| + index = 0
|
| + for run_command in self.run_commands:
|
| + setattr(self, 'prof%d' % index, self.profile_name(index))
|
| + c = (
|
| + self.log_execute,
|
| + self.log_display,
|
| + run_command,
|
| + self.logfile_name(index),
|
| + )
|
| + commands.append(c)
|
| + index = index + 1
|
| +
|
| + commands.extend([
|
| + (os.chdir, 'cd %%s', self.orig_cwd),
|
| + ])
|
| +
|
| + if not os.environ.get('PRESERVE'):
|
| + commands.extend(removals)
|
| +
|
| + commands.append((shutil.rmtree, 'rm -rf %%s', self.tmpdir))
|
| +
|
| + self.run_command_list(commands, self.__dict__)
|
| +
|
| + self.scons = save_scons
|
| + self.scons_lib_dir = save_scons_lib_dir
|
| + self.scons_wrapper = save_scons_wrapper
|
| +
|
| + #
|
| +
|
| + def help_time(self):
|
| + help = """\
|
| + Usage: scons-time time [OPTIONS] FILE [...]
|
| +
|
| + -C DIR, --chdir=DIR Change to DIR before looking for files
|
| + -f FILE, --file=FILE Read configuration from specified FILE
|
| + --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
|
| + -h, --help Print this help and exit
|
| + -p STRING, --prefix=STRING Use STRING as log file/profile prefix
|
| + -t NUMBER, --tail=NUMBER Only report the last NUMBER files
|
| + --which=TIMER Plot timings for TIMER: total,
|
| + SConscripts, SCons, commands.
|
| + """
|
| + sys.stdout.write(self.outdent(help))
|
| + sys.stdout.flush()
|
| +
|
| + def do_time(self, argv):
|
| +
|
| + format = 'ascii'
|
| + logfile_path = lambda x: x
|
| + tail = None
|
| + which = 'total'
|
| +
|
| + short_opts = '?C:f:hp:t:'
|
| +
|
| + long_opts = [
|
| + 'chdir=',
|
| + 'file=',
|
| + 'fmt=',
|
| + 'format=',
|
| + 'help',
|
| + 'prefix=',
|
| + 'tail=',
|
| + 'title=',
|
| + 'which=',
|
| + ]
|
| +
|
| + opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
|
| +
|
| + for o, a in opts:
|
| + if o in ('-C', '--chdir'):
|
| + self.chdir = a
|
| + elif o in ('-f', '--file'):
|
| + self.config_file = a
|
| + elif o in ('--fmt', '--format'):
|
| + format = a
|
| + elif o in ('-?', '-h', '--help'):
|
| + self.do_help(['help', 'time'])
|
| + sys.exit(0)
|
| + elif o in ('-p', '--prefix'):
|
| + self.prefix = a
|
| + elif o in ('-t', '--tail'):
|
| + tail = int(a)
|
| + elif o in ('--title',):
|
| + self.title = a
|
| + elif o in ('--which',):
|
| + if not a in self.time_strings.keys():
|
| + sys.stderr.write('%s: time: Unrecognized timer "%s".\n' % (self.name, a))
|
| + sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| + which = a
|
| +
|
| + if self.config_file:
|
| + HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__)
|
| +
|
| + if self.chdir:
|
| + os.chdir(self.chdir)
|
| + logfile_path = lambda x: os.path.join(self.chdir, x)
|
| +
|
| + if not args:
|
| +
|
| + pattern = '%s*.log' % self.prefix
|
| + args = self.args_to_files([pattern], tail)
|
| +
|
| + if not args:
|
| + if self.chdir:
|
| + directory = self.chdir
|
| + else:
|
| + directory = os.getcwd()
|
| +
|
| + sys.stderr.write('%s: time: No arguments specified.\n' % self.name)
|
| + sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory))
|
| + sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name))
|
| + sys.exit(1)
|
| +
|
| + else:
|
| +
|
| + args = self.args_to_files(args, tail)
|
| +
|
| + cwd_ = os.getcwd() + os.sep
|
| +
|
| + if format == 'ascii':
|
| +
|
| + columns = ("Total", "SConscripts", "SCons", "commands")
|
| + self.ascii_table(args, columns, self.get_debug_times, logfile_path)
|
| +
|
| + elif format == 'gnuplot':
|
| +
|
| + results = self.collect_results(args, self.get_debug_times,
|
| + self.time_strings[which])
|
| +
|
| + self.gnuplot_results(results, fmt='%s %.6f')
|
| +
|
| + else:
|
| +
|
| + sys.stderr.write('%s: time: Unknown format "%s".\n' % (self.name, format))
|
| + sys.exit(1)
|
| +
|
| +if __name__ == '__main__':
|
| + opts, args = getopt.getopt(sys.argv[1:], 'h?V', ['help', 'version'])
|
| +
|
| + ST = SConsTimer()
|
| +
|
| + for o, a in opts:
|
| + if o in ('-?', '-h', '--help'):
|
| + ST.do_help(['help'])
|
| + sys.exit(0)
|
| + elif o in ('-V', '--version'):
|
| + sys.stdout.write('scons-time version\n')
|
| + sys.exit(0)
|
| +
|
| + if not args:
|
| + sys.stderr.write('Type "%s help" for usage.\n' % ST.name)
|
| + sys.exit(1)
|
| +
|
| + ST.execute_subcommand(args)
|
| +
|
| +# Local Variables:
|
| +# tab-width:4
|
| +# indent-tabs-mode:nil
|
| +# End:
|
| +# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
|
| Property changes on: scons-2.0.1/script/scons-time
|
| ___________________________________________________________________
|
| Added: svn:executable
|
| + *
|
|
|
|
|