forked from markhpc/gdbpmp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
common.py
82 lines (68 loc) · 3.81 KB
/
common.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python3
# Copyright (c) 2017 Mark Nelson
import argparse
import pickle
import shutil
from gdbtypes import GDBFunction, GDBThread
def parse_args(args=None):
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-i', '--input', required=False, type=str, help='Read collected samples from this file.')
group.add_argument('-p', '--pid', required=False, type=int, help='PID of the process to connect to.')
parser.add_argument('-s', '--sleep', required=False, type=float, default=0.01, help='Period of time to sleep between samples in seconds.')
parser.add_argument('-n', '--samples', required=False, type=int, default=1000, help='The number of samples to collect.')
parser.add_argument('-m', '--match', required=False, type=str, help='A comma separated list of strings to match with threads')
parser.add_argument('-x', '--exclude', required=False, type=str, help='A comma separated list of strings to match when excluding threads.')
parser.add_argument('-o', '--output', required=False, type=str, help='Write collected samples to this file.')
parser.add_argument('-g', '--gdb_path', required=False, type=str, default='/usr/bin/gdb', help='Path to the GDB executable.')
parser.add_argument('-t', '--threshold', required=False, type=float, default=0.1, help='Ignore results below the threshold when making the callgraph.')
parser.add_argument('-v', '--invert', required=False, action='store_true', help='Print inverted callgraph.')
parser.add_argument('-d', '--detachattach', required=False, action='store_true', help='Use the detach/attach trace mode. Slower, but more compatible.')
parser.add_argument('-w', '--max_width', required=False, type=int, default=shutil.get_terminal_size().columns, help='Set the display width (default is terminal width)')
parser.add_argument('-r', '--truncate', required=False, action='store_true', help="Truncate lines to the terminal width")
if args:
return parser.parse_args(args)
else:
return parser.parse_args()
def print_callgraph(ctx, threads):
print("");
for thn, gdbth in sorted(threads.items()):
samples = gdbth.function.get_samples(True)
print("")
print(("Thread: %s (%s) - %s samples " % (gdbth.num, gdbth.name, samples)))
print("")
gdbth.function.print_percent(ctx, "", samples, True)
def print_inverted_callgraph(ctx, threads):
print("")
for thn, gdbth in sorted(threads.items()):
samples = gdbth.function.get_samples(True)
igdbth = invert_thread(gdbth)
print("")
print(("Thread: %s (%s) - %s samples " % (igdbth.num, igdbth.name, samples)))
print("")
igdbth.function.print_percent(ctx, "", samples, False)
def invert_thread(gdbth):
inverted_func = GDBFunction(None, 2)
invert_function(gdbth.function, inverted_func)
return GDBThread(gdbth.name, gdbth.num, gdbth.ptid, inverted_func)
def invert_function(input_func, base_func):
ret = []
# If we spent time directly in this function, add it to the base_func
if input_func.count > 0:
func = base_func.get_or_add_func(input_func.name)
func.count += input_func.count
ret.append((func, input_func.count))
# iterate over the subfunctions
for subfunction in input_func.subfunctions:
tree_funcs = invert_function(subfunction, base_func)
for (tree_func, count) in tree_funcs:
func = tree_func.get_or_add_func(input_func.name)
func.count += count
ret.append((func, count))
return ret
def dump_threads(threads, filename):
with open(filename, 'wb') as handle:
pickle.dump(threads, handle, protocol=pickle.HIGHEST_PROTOCOL)
def load_threads(filename):
with open(filename, 'rb') as handle:
return pickle.load(handle)