cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stackcollapse.py (4408B)


      1# stackcollapse.py - format perf samples with one line per distinct call stack
      2# SPDX-License-Identifier: GPL-2.0
      3#
      4# This script's output has two space-separated fields.  The first is a semicolon
      5# separated stack including the program name (from the "comm" field) and the
      6# function names from the call stack.  The second is a count:
      7#
      8#  swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 2
      9#
     10# The file is sorted according to the first field.
     11#
     12# Input may be created and processed using:
     13#
     14#  perf record -a -g -F 99 sleep 60
     15#  perf script report stackcollapse > out.stacks-folded
     16#
     17# (perf script record stackcollapse works too).
     18#
     19# Written by Paolo Bonzini <pbonzini@redhat.com>
     20# Based on Brendan Gregg's stackcollapse-perf.pl script.
     21
     22from __future__ import print_function
     23
     24import os
     25import sys
     26from collections import defaultdict
     27from optparse import OptionParser, make_option
     28
     29sys.path.append(os.environ['PERF_EXEC_PATH'] + \
     30    '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
     31
     32from perf_trace_context import *
     33from Core import *
     34from EventClass import *
     35
     36# command line parsing
     37
     38option_list = [
     39    # formatting options for the bottom entry of the stack
     40    make_option("--include-tid", dest="include_tid",
     41                 action="store_true", default=False,
     42                 help="include thread id in stack"),
     43    make_option("--include-pid", dest="include_pid",
     44                 action="store_true", default=False,
     45                 help="include process id in stack"),
     46    make_option("--no-comm", dest="include_comm",
     47                 action="store_false", default=True,
     48                 help="do not separate stacks according to comm"),
     49    make_option("--tidy-java", dest="tidy_java",
     50                 action="store_true", default=False,
     51                 help="beautify Java signatures"),
     52    make_option("--kernel", dest="annotate_kernel",
     53                 action="store_true", default=False,
     54                 help="annotate kernel functions with _[k]")
     55]
     56
     57parser = OptionParser(option_list=option_list)
     58(opts, args) = parser.parse_args()
     59
     60if len(args) != 0:
     61    parser.error("unexpected command line argument")
     62if opts.include_tid and not opts.include_comm:
     63    parser.error("requesting tid but not comm is invalid")
     64if opts.include_pid and not opts.include_comm:
     65    parser.error("requesting pid but not comm is invalid")
     66
     67# event handlers
     68
     69lines = defaultdict(lambda: 0)
     70
     71def process_event(param_dict):
     72    def tidy_function_name(sym, dso):
     73        if sym is None:
     74            sym = '[unknown]'
     75
     76        sym = sym.replace(';', ':')
     77        if opts.tidy_java:
     78            # the original stackcollapse-perf.pl script gives the
     79            # example of converting this:
     80            #    Lorg/mozilla/javascript/MemberBox;.<init>(Ljava/lang/reflect/Method;)V
     81            # to this:
     82            #    org/mozilla/javascript/MemberBox:.init
     83            sym = sym.replace('<', '')
     84            sym = sym.replace('>', '')
     85            if sym[0] == 'L' and sym.find('/'):
     86                sym = sym[1:]
     87            try:
     88                sym = sym[:sym.index('(')]
     89            except ValueError:
     90                pass
     91
     92        if opts.annotate_kernel and dso == '[kernel.kallsyms]':
     93            return sym + '_[k]'
     94        else:
     95            return sym
     96
     97    stack = list()
     98    if 'callchain' in param_dict:
     99        for entry in param_dict['callchain']:
    100            entry.setdefault('sym', dict())
    101            entry['sym'].setdefault('name', None)
    102            entry.setdefault('dso', None)
    103            stack.append(tidy_function_name(entry['sym']['name'],
    104                                            entry['dso']))
    105    else:
    106        param_dict.setdefault('symbol', None)
    107        param_dict.setdefault('dso', None)
    108        stack.append(tidy_function_name(param_dict['symbol'],
    109                                        param_dict['dso']))
    110
    111    if opts.include_comm:
    112        comm = param_dict["comm"].replace(' ', '_')
    113        sep = "-"
    114        if opts.include_pid:
    115            comm = comm + sep + str(param_dict['sample']['pid'])
    116            sep = "/"
    117        if opts.include_tid:
    118            comm = comm + sep + str(param_dict['sample']['tid'])
    119        stack.append(comm)
    120
    121    stack_string = ';'.join(reversed(stack))
    122    lines[stack_string] = lines[stack_string] + 1
    123
    124def trace_end():
    125    list = sorted(lines)
    126    for stack in list:
    127        print("%s %d" % (stack, lines[stack]))