def action_analyze()

in utils/ptreetime/ptreetime.py [0:0]


def action_analyze(name, args):
    """analyze a ptreetime data file"""
    parser = optparse.OptionParser("""\
usage: %%prog %(name)s [options] <path>

Execute the given command and track the execution time of all the processes
which are created during the execution.""" % locals())
    parser.add_option("-f", "--focus", dest="focus",
                      help="focus on the given process name",
                      action="store", default=None)
    parser.add_option("--show-tree", dest="show_tree",
                      help="Print the entire call tree",
                      action="store_true")
    parser.add_option("", "--gen-report", dest="lnt_report_path",
                      help="generate an LNT report",
                      action="store", default=None)
    parser.add_option("", "--report-machine", dest="report_machine",
                      help="machine name to include in the LNT report",
                      action="store", default=None)
    parser.add_option("", "--report-run-order", dest="report_run_order",
                      help="run order to include in the LNT report",
                      action="store", default=None)
    parser.add_option("", "--report-sub-arg", dest="report_sub_args",
                      help="add an argument replacement pattern",
                      metavar="PATTERN=REPLACEMENT",
                      action="append", default=[])

    (opts, args) = parser.parse_args(args)

    if len(args) < 1:
       parser.error("invalid number of arguments")
    if opts.lnt_report_path:
        if opts.report_machine is None:
            parser.error("--report-machine is required with --gen-report")
        if opts.report_run_order is None:
            parser.error("--report-run-order is required with --gen-report")
    else:
        if opts.report_machine is not None:
            parser.error("--report-machine is unused without --gen-report")
        if opts.report_run_order is not None:
            parser.error("--report-run-order is unused without --gen-report")
        if opts.report_sub_args:
            parser.error("--report-sub-arg is unused without --gen-report")

    paths = args

    def find_focused_roots(node):
        # If this is a focused node, add it to the list.
        if opts.focus is None or node.name == opts.focus:
            focused_roots.append(node)
            return

        # Otherwise, recurse on each child.
        for child in node.children:
            find_focused_roots(child)
    focused_roots = []
    for path in paths:
        # Load each file.
        target_root,roots,active_processes = _parse_event_log(path)
        find_focused_roots(target_root)

    # For each root, show the flattened performance.
    def print_node(node, depth):
        # If this node isn't complete, ignore it.
        if node.start_timestamp is None:
            warning("ignoring incomplete node %r (didn't see create)" % (
                    (node.pid, node.name),))
            return
        if node.exit_timestamp is None:
            warning("ignoring incomplete node %r (didn't see exit)" % (
                    (node.pid,),))
            return

        indent = '  '*depth
        wall = node.total_wall_time
        user = node.total_user_time
        sys = node.total_system_time
        startlag = node.startlag
        exitlag = node.exitlag
        if opts.show_tree:
            print ('%s%s -- wall: %.4fs, user: %.4fs, sys: %.4fs, '
                   'startlag: %.4fs, exitlag: %.4fs') % (
                indent, node.name, wall, user, sys, startlag, exitlag)

        key = '%s @ %d' % (node.name, depth)
        aggregate_info = aggregate.get(key)
        if aggregate_info is None:
            aggregate[key] = aggregate_info = {
                'name' : key,
                'wall' : 0.0,
                'user' : 0.0,
                'sys' : 0.0,
                'startlag' : 0.0,
                'exitlag' : 0.0,
                'count' : 0 }
        aggregate_info['wall'] += wall
        aggregate_info['user'] += user
        aggregate_info['sys'] += sys
        aggregate_info['startlag'] += startlag
        aggregate_info['exitlag'] += exitlag
        aggregate_info['count'] += 1

        for c in node.children:
            print_node(c, depth+1)

    if not focused_roots:
        parser.error("no roots found!")

    aggregate = {}
    for node in focused_roots:
       print_node(node, depth=0)
       if node is not focused_roots[-1]:
          print

    print
    print 'Aggregate Times'
    print '---------------'
    items = aggregate.values()
    items.sort(key = lambda i: i['wall'],
               reverse = True)
    name_length = max(len(item['name'])
                      for item in items)
    for item in items:
       print ('%-*s -- wall: %8.4fs, user: %8.4fs, sys: %8.4fs, '
              'startlag: %8.4fs, exitlag: %.4fs, count: %d') % (
          name_length, item['name'], item['wall'], item['user'], item['sys'],
          item['startlag'], item['exitlag'], item['count'])

    # Write out an LNT test report with the data, if requested.
    if opts.lnt_report_path:
        import lnt.testing

        # Build the regular expression substitution arguments.
        substitution_args = []
        for value in opts.report_sub_args:
            if '=' in value:
                pattern,replacement = value.split('=',1)
            else:
                pattern,replacement = value,''
            substitution_args.append((re.compile(pattern), replacement))

        # First, organize all the nodes by deriving a test name key for them.
        def group_node_and_children(node, depth = 0):
            # Ignore incomplete nodes.
            if node.start_timestamp is None or node.exit_timestamp is None:
                return

            args = node.args
            if args is not None:
                # If this is a clang -cc1 invocation, do some special stuff to
                # normalize.
                if node.name == "clang" and args and args[1] == '-cc1':
                    triple_index = args.index('-triple')
                    main_file_name_index = args.index('-main-file-name')
                    args = (
                        args[:2] +
                        args[triple_index:triple_index+2] + \
                        args[main_file_name_index:main_file_name_index+2])


                # Apply substitutions to each argument.
                def substitute(arg):
                    for pattern_re,replacement in substitution_args:
                        arg = pattern_re.sub(replacement, arg)
                    return arg
                args = [substitute(arg)
                        for arg in args]

                # Eliminate empty arguments.
                args = filter(None, args)

            key = '%s(depth=%d,args=%r)' % (node.name, depth, args)
            items = nodes_by_key.get(key)
            if items is None:
                nodes_by_key[key] = items = []
            items.append(node)

            for child in node.children:
                group_node_and_children(child, depth+1)
        nodes_by_key = {}
        for node in focused_roots:
            group_node_and_children(node)

        tag = "compile"
        run_info = { "tag" : tag,
                     "run_order" : opts.report_run_order }
        machine = lnt.testing.Machine(opts.report_machine, {})
        run = lnt.testing.Run(datetime.datetime.fromtimestamp(
                target_root.start_timestamp_in_seconds).\
                                  strftime('%Y-%m-%d %H:%M:%S'),
                              datetime.datetime.fromtimestamp(
                target_root.exit_timestamp_in_seconds).\
                                  strftime('%Y-%m-%d %H:%M:%S'),
                              info=run_info)

        # We report in a scheme compatible with the compile time suite.
        testsamples = []
        for key,nodes in nodes_by_key.items():
            for subkey,accessor in (('wall', 'total_wall_time'),
                                    ('user', 'total_user_time'),
                                    ('sys', 'total_system_time')):
                values = [getattr(node, accessor)
                          for node in nodes]
                name = '%s.%s.%s' % (tag, key, subkey)
                testsamples.append(lnt.testing.TestSamples(
                        name, values))

        report = lnt.testing.Report(machine, run, testsamples)
        with open(opts.lnt_report_path, "w") as f:
            print >>f, report.render()