Whamcloud - gitweb
LU-12461 contrib: Add epython scripts for crash dump analysis
[fs/lustre-release.git] / contrib / debug_tools / epython_scripts / uniqueStacktrace.py
1 #!/usr/bin/env python
2 """
3 Copyright (c) 2015-2019 Cray Inc. All Rights Reserved.
4 Utility to print unique stack traces
5 """
6
7 import re
8 import sys
9 import StringIO
10 import argparse
11 from pykdump.API import exec_crash_command
12
13 description_short = 'Print stack traces for each task.'
14
15 # outer loop indentifies PIDs
16 # inner loop looks for # until
17 # another PID is found
18 def sortInput(swapper, input):
19
20
21     ps = re.compile("^PID:\s+(\d+)\s+TASK:\s+([0-9A-Fa-f]+).*")
22     n = re.compile("^#")
23     swap = re.compile((".*\"swapper/[0-9]+\""))
24     info = dict()
25     PID = ""
26     STK = ""
27     tmp = ""
28
29     # Outer to check for PIDs
30     # this loop never breaks;
31     for line in input:
32         line = line.strip()
33
34         # Inner loop to check for # signs indicating lines we want.
35         # Having two loops allow for the PID and TSK to be associated
36         # with  a particular trace.
37         # This loop breaks if a new PID is found (meaning the end of the
38         # current trace) or if there are no more lines available
39         while True:
40             if ps.match(line): break;
41             line = line.strip()
42             if n.match(line):
43                 line = line.split()
44                 tmp += " ".join([line[2], line[3], line[4]])
45                 if len(line) == 6 : tmp += " " + line[5]
46                 tmp += '\n\t'
47             line = input.readline()
48             if not line: break
49
50         if tmp :
51             if tmp in info:
52                 info[tmp].append((PID,STK))
53             else:
54                 info[tmp] = [(PID,STK)]
55
56         m = ps.match(line)
57         if m:
58             PID, STK = m.group(1), m.group(2)
59             tmp = ""
60
61             # if it's swapper line move on
62             # this prevents entry into inner loop
63             if not swapper and swap.match(line):
64                 line = input.readline()
65
66     sort = sorted(info.items(), key=lambda info: len(info[1]))
67     return sort
68
69 def printRes(sort, printpid, printptr):
70     """
71     Prints out individual stack traces from lowest to highest.
72     """
73     for stack_trace, ptask_list in sort:
74         if printpid and not printptr:
75             print "PID: %s" % (', '.join(p[0] for p in ptask_list))
76         elif printpid and printptr:
77             print "PID, TSK: %s" % (', '.join(p[0] + ': ' + p[1] for p in ptask_list))
78         elif not printpid and printptr:
79             print "TSK: %s" % (', '.join(p[1] for p in ptask_list))
80         print "TASKS: %d" %(len(ptask_list))
81         print "\t%s" %(stack_trace)
82
83
84 def main():
85     parser = argparse.ArgumentParser()
86
87     parser.add_argument("-p", "--print-pid",
88                         action="store_true", dest="printpid", default=False,
89                         help="Print PIDS corresponding to each ST")
90     parser.add_argument("-q", "--print-taskpntr",
91                         action="store_true", dest="printptr", default=False,
92                         help="Print the task pointers for each ST")
93     parser.add_argument("-s", "--swapper",
94                         action="store_true", dest="swapper", default=False,
95                         help="Print swapper processes")
96     parser.add_argument("task_select", metavar="task_selection", nargs="*",
97                         help="task selection argument (passed to foreach cmd)")
98
99     args = parser.parse_args()
100
101     com = "foreach {ts:s} bt".format(ts=" ".join(args.task_select))
102
103     result = exec_crash_command(com)
104     input = StringIO.StringIO(result)
105     printRes(sortInput(args.swapper, input), args.printpid, args.printptr)
106
107 if __name__ == '__main__':
108     main()