#!/usr/bin/env python3 | |
from collections import defaultdict | |
import sys | |
def parse_stacks(bt_file): | |
stack = [] | |
for line in bt_file: | |
if line.strip(): | |
stack.append(line) | |
else: | |
yield ''.join(stack) | |
stack = [] | |
if stack: | |
yield ''.join(stack) | |
def stack_key(stack): | |
if not stack.startswith('Thread '): | |
return stack | |
lines = stack.splitlines() | |
if len(lines) < 2: | |
return stack | |
key = [] | |
for line in lines[1:]: | |
parts = line.split() | |
if len(parts) < 2: | |
return stack | |
key.append(parts[1]) | |
return '\n'.join(key) | |
if __name__ == '__main__': | |
if len(sys.argv) < 2: | |
print('Usage: %s <back_trace.txt>\n\n' | |
'Note: back_trace.txt can be obtained using the following command: ' | |
'`gdb -p <:pid> -batch -ex "thread apply all bt" > back_trace.txt`' % sys.argv[0]) | |
sys.exit(0) | |
if sys.argv[1] == '-': | |
bt_file = sys.stdin | |
else: | |
bt_file = open(sys.argv[1]) | |
stack_list = list(parse_stacks(bt_file)) | |
stack_count = defaultdict(int) | |
for stack in stack_list: | |
stack_count[stack_key(stack)] += 1 | |
printed = {} | |
for stack in stack_list: | |
key = stack_key(stack) | |
if key in printed: | |
continue | |
if stack.startswith('[New LWP '): | |
continue | |
printed[key] = True | |
stack = stack.replace(':\n', ': [Total %d]\n' % stack_count[key], 1) | |
print(stack) |