Whamcloud - gitweb
LU-12461 contrib: Add epython scripts for crash dump analysis
[fs/lustre-release.git] / contrib / debug_tools / epython_scripts / uniqueStacktrace.py
diff --git a/contrib/debug_tools/epython_scripts/uniqueStacktrace.py b/contrib/debug_tools/epython_scripts/uniqueStacktrace.py
new file mode 100644 (file)
index 0000000..415aee1
--- /dev/null
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+"""
+Copyright (c) 2015-2019 Cray Inc. All Rights Reserved.
+Utility to print unique stack traces
+"""
+
+import re
+import sys
+import StringIO
+import argparse
+from pykdump.API import exec_crash_command
+
+description_short = 'Print stack traces for each task.'
+
+# outer loop indentifies PIDs
+# inner loop looks for # until
+# another PID is found
+def sortInput(swapper, input):
+
+
+    ps = re.compile("^PID:\s+(\d+)\s+TASK:\s+([0-9A-Fa-f]+).*")
+    n = re.compile("^#")
+    swap = re.compile((".*\"swapper/[0-9]+\""))
+    info = dict()
+    PID = ""
+    STK = ""
+    tmp = ""
+
+    # Outer to check for PIDs
+    # this loop never breaks;
+    for line in input:
+        line = line.strip()
+
+        # Inner loop to check for # signs indicating lines we want.
+        # Having two loops allow for the PID and TSK to be associated
+        # with  a particular trace.
+        # This loop breaks if a new PID is found (meaning the end of the
+        # current trace) or if there are no more lines available
+        while True:
+            if ps.match(line): break;
+            line = line.strip()
+            if n.match(line):
+                line = line.split()
+                tmp += " ".join([line[2], line[3], line[4]])
+                if len(line) == 6 : tmp += " " + line[5]
+                tmp += '\n\t'
+            line = input.readline()
+            if not line: break
+
+        if tmp :
+            if tmp in info:
+                info[tmp].append((PID,STK))
+            else:
+                info[tmp] = [(PID,STK)]
+
+        m = ps.match(line)
+        if m:
+            PID, STK = m.group(1), m.group(2)
+            tmp = ""
+
+            # if it's swapper line move on
+            # this prevents entry into inner loop
+            if not swapper and swap.match(line):
+                line = input.readline()
+
+    sort = sorted(info.items(), key=lambda info: len(info[1]))
+    return sort
+
+def printRes(sort, printpid, printptr):
+    """
+    Prints out individual stack traces from lowest to highest.
+    """
+    for stack_trace, ptask_list in sort:
+        if printpid and not printptr:
+            print "PID: %s" % (', '.join(p[0] for p in ptask_list))
+        elif printpid and printptr:
+            print "PID, TSK: %s" % (', '.join(p[0] + ': ' + p[1] for p in ptask_list))
+        elif not printpid and printptr:
+            print "TSK: %s" % (', '.join(p[1] for p in ptask_list))
+        print "TASKS: %d" %(len(ptask_list))
+        print "\t%s" %(stack_trace)
+
+
+def main():
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument("-p", "--print-pid",
+                        action="store_true", dest="printpid", default=False,
+                        help="Print PIDS corresponding to each ST")
+    parser.add_argument("-q", "--print-taskpntr",
+                        action="store_true", dest="printptr", default=False,
+                        help="Print the task pointers for each ST")
+    parser.add_argument("-s", "--swapper",
+                        action="store_true", dest="swapper", default=False,
+                        help="Print swapper processes")
+    parser.add_argument("task_select", metavar="task_selection", nargs="*",
+                        help="task selection argument (passed to foreach cmd)")
+
+    args = parser.parse_args()
+
+    com = "foreach {ts:s} bt".format(ts=" ".join(args.task_select))
+
+    result = exec_crash_command(com)
+    input = StringIO.StringIO(result)
+    printRes(sortInput(args.swapper, input), args.printpid, args.printptr)
+
+if __name__ == '__main__':
+    main()