From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751569AbcDOKHH (ORCPT ); Fri, 15 Apr 2016 06:07:07 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:34147 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751186AbcDOKHE (ORCPT ); Fri, 15 Apr 2016 06:07:04 -0400 Subject: ping Re: [PATCH] perf script: Add stackcollapse.py script To: linux-kernel@vger.kernel.org References: <1460467573-22989-1-git-send-email-pbonzini@redhat.com> Cc: Jiri Olsa , Arnaldo Carvalho de Melo , Brendan Gregg From: Paolo Bonzini Message-ID: <57107A30.7090809@redhat.com> Date: Fri, 15 Apr 2016 07:20:48 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.7.1 MIME-Version: 1.0 In-Reply-To: <1460467573-22989-1-git-send-email-pbonzini@redhat.com> Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 12/04/2016 15:26, Paolo Bonzini wrote: > Add stackcollapse.py script as an example of parsing call chains, and > also of using optparse to access command line options. > > The flame graph tools include a set of scripts that parse output from > various tools (including "perf script"), remove the offsets in the > function and collapse each stack to a single line. The website also says > "perf report could have a report style [...] that output folded stacks > directly, obviating the need for stackcollapse-perf.pl", so here it is. > > This script is a Python rewrite of stackcollapse-perf.pl, using the perf > scripting interface to access the perf data directly from Python. > > Cc: Jiri Olsa > Cc: Arnaldo Carvalho de Melo > Cc: Brendan Gregg > Signed-off-by: Paolo Bonzini Sorry for the very early ping, I'm going on vacation and I'm afraid the next time I'd be able to ping would be too late for 4.7. :) Paolo > --- > tools/perf/scripts/python/bin/stackcollapse-record | 8 ++ > tools/perf/scripts/python/bin/stackcollapse-report | 3 + > tools/perf/scripts/python/stackcollapse.py | 127 +++++++++++++++++++++ > 3 files changed, 138 insertions(+) > create mode 100755 tools/perf/scripts/python/bin/stackcollapse-record > create mode 100755 tools/perf/scripts/python/bin/stackcollapse-report > create mode 100755 tools/perf/scripts/python/stackcollapse.py > > diff --git a/tools/perf/scripts/python/bin/stackcollapse-record b/tools/perf/scripts/python/bin/stackcollapse-record > new file mode 100755 > index 000000000000..9d8f9f0f3a17 > --- /dev/null > +++ b/tools/perf/scripts/python/bin/stackcollapse-record > @@ -0,0 +1,8 @@ > +#!/bin/sh > + > +# > +# stackcollapse.py can cover all type of perf samples including > +# the tracepoints, so no special record requirements, just record what > +# you want to analyze. > +# > +perf record "$@" > diff --git a/tools/perf/scripts/python/bin/stackcollapse-report b/tools/perf/scripts/python/bin/stackcollapse-report > new file mode 100755 > index 000000000000..356b9656393d > --- /dev/null > +++ b/tools/perf/scripts/python/bin/stackcollapse-report > @@ -0,0 +1,3 @@ > +#!/bin/sh > +# description: produce callgraphs in short form for scripting use > +perf script -s "$PERF_EXEC_PATH"/scripts/python/stackcollapse.py -- "$@" > diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py > new file mode 100755 > index 000000000000..a2dfcda41ae6 > --- /dev/null > +++ b/tools/perf/scripts/python/stackcollapse.py > @@ -0,0 +1,127 @@ > +#!/usr/bin/perl -w > +# > +# stackcollapse.py - format perf samples with one line per distinct call stack > +# > +# This script's output has two space-separated fields. The first is a semicolon > +# separated stack including the program name (from the "comm" field) and the > +# function names from the call stack. The second is a count: > +# > +# swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 2 > +# > +# The file is sorted according to the first field. > +# > +# Input may be created and processed using: > +# > +# perf record -a -g -F 99 sleep 60 > +# perf script report stackcollapse > out.stacks-folded > +# > +# (perf script record stackcollapse works too). > +# > +# Written by Paolo Bonzini > +# Based on Brendan Gregg's stackcollapse-perf.pl script. > + > +import os > +import sys > +from collections import defaultdict > +from optparse import OptionParser, make_option > + > +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ > + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') > + > +from perf_trace_context import * > +from Core import * > +from EventClass import * > + > +# command line parsing > + > +option_list = [ > + # formatting options for the bottom entry of the stack > + make_option("--include-tid", dest="include_tid", > + action="store_true", default=False, > + help="include thread id in stack"), > + make_option("--include-pid", dest="include_pid", > + action="store_true", default=False, > + help="include process id in stack"), > + make_option("--no-comm", dest="include_comm", > + action="store_false", default=True, > + help="do not separate stacks according to comm"), > + make_option("--tidy-java", dest="tidy_java", > + action="store_true", default=False, > + help="beautify Java signatures"), > + make_option("--kernel", dest="annotate_kernel", > + action="store_true", default=False, > + help="annotate kernel functions with _[k]") > +] > + > +parser = OptionParser(option_list=option_list) > +(opts, args) = parser.parse_args() > + > +if len(args) != 0: > + parser.error("unexpected command line argument") > +if opts.include_tid and not opts.include_comm: > + parser.error("requesting tid but not comm is invalid") > +if opts.include_pid and not opts.include_comm: > + parser.error("requesting pid but not comm is invalid") > + > +# event handlers > + > +lines = defaultdict(lambda: 0) > + > +def process_event(param_dict): > + def tidy_function_name(sym, dso): > + if sym is None: > + sym = '[unknown]' > + > + sym = sym.replace(';', ':') > + if opts.tidy_java: > + # the original stackcollapse-perf.pl script gives the > + # example of converting this: > + # Lorg/mozilla/javascript/MemberBox;.(Ljava/lang/reflect/Method;)V > + # to this: > + # org/mozilla/javascript/MemberBox:.init > + sym = sym.replace('<', '') > + sym = sym.replace('>', '') > + if sym[0] == 'L' and sym.find('/'): > + sym = sym[1:] > + try: > + sym = sym[:sym.index('(')] > + except ValueError: > + pass > + > + if opts.annotate_kernel and dso == '[kernel.kallsyms]': > + return sym + '_[k]' > + else: > + return sym > + > + stack = list() > + if 'callchain' in param_dict: > + for entry in param_dict['callchain']: > + entry.setdefault('sym', dict()) > + entry['sym'].setdefault('name', None) > + entry.setdefault('dso', None) > + stack.append(tidy_function_name(entry['sym']['name'], > + entry['dso'])) > + else: > + param_dict.setdefault('symbol', None) > + param_dict.setdefault('dso', None) > + stack.append(tidy_function_name(param_dict['symbol'], > + param_dict['dso'])) > + > + if opts.include_comm: > + comm = param_dict["comm"].replace(' ', '_') > + sep = "-" > + if opts.include_pid: > + comm = comm + sep + str(param_dict['sample']['pid']) > + sep = "/" > + if opts.include_tid: > + comm = comm + sep + str(param_dict['sample']['tid']) > + stack.append(comm) > + > + stack_string = ';'.join(reversed(stack)) > + lines[stack_string] = lines[stack_string] + 1 > + > +def trace_end(): > + list = lines.keys() > + list.sort() > + for stack in list: > + print "%s %d" % (stack, lines[stack]) >