def run(pid): bpf = BPF(text=text) attach(bpf, pid) init_stacks = bpf["init_stacks"] stacks = bpf["stacks"] locks = bpf["locks"] mutex_lock_hist = bpf["mutex_lock_hist"] mutex_wait_hist = bpf["mutex_wait_hist"] syms = ProcessSymbols(pid=pid) while True: sleep(5) syms.refresh_code_ranges() mutex_ids = {} next_mutex_id = 1 for k, v in init_stacks.items(): mutex_id = "#%d" % next_mutex_id next_mutex_id += 1 mutex_ids[k.value] = mutex_id print("init stack for mutex %x (%s)" % (k.value, mutex_id)) print_stack(syms, stacks, v.value) print("") grouper = lambda (k, v): k.tid sorted_by_thread = sorted(locks.items(), key=grouper) locks_by_thread = itertools.groupby(sorted_by_thread, grouper) for tid, items in locks_by_thread: print("thread %d" % tid) for k, v in sorted(items, key=lambda (k, v): -v.wait_time_ns): mutex_descr = mutex_ids[ k.mtx] if k.mtx in mutex_ids else syms.decode_addr(k.mtx) # TODO Print a nicely formatted line with the mutex description, wait time, # hold time, enter count, and stack (use print_stack) print("") mutex_wait_hist.print_log2_hist(val_type="wait time (us)") mutex_lock_hist.print_log2_hist(val_type="hold time (us)")
def run(pid): bpf = BPF(text=text) attach(bpf, pid) init_stacks = bpf["init_stacks"] stacks = bpf["stacks"] locks = bpf["locks"] mutex_lock_hist = bpf["mutex_lock_hist"] mutex_wait_hist = bpf["mutex_wait_hist"] syms = ProcessSymbols(pid=pid) while True: sleep(5) syms.refresh_code_ranges() mutex_ids = {} next_mutex_id = 1 for k, v in init_stacks.items(): mutex_id = "#%d" % next_mutex_id next_mutex_id += 1 mutex_ids[k.value] = mutex_id print("init stack for mutex %x (%s)" % (k.value, mutex_id)) print_stack(syms, stacks, v.value) print("") grouper = lambda (k, v): k.tid sorted_by_thread = sorted(locks.items(), key=grouper) locks_by_thread = itertools.groupby(sorted_by_thread, grouper) for tid, items in locks_by_thread: print("thread %d" % tid) for k, v in sorted(items, key=lambda (k, v): -v.wait_time_ns): mutex_descr = mutex_ids[k.mtx] if k.mtx in mutex_ids else syms.decode_addr(k.mtx) print("\tmutex %s ::: wait time %.2fus ::: hold time %.2fus ::: enter count %d" % (mutex_descr, v.wait_time_ns/1000.0, v.lock_time_ns/1000.0, v.enter_count)) print_stack(syms, stacks, k.lock_stack_id) print("") mutex_wait_hist.print_log2_hist(val_type="wait time (us)") mutex_lock_hist.print_log2_hist(val_type="hold time (us)")
class UStackDecoder(object): def __init__(self, pid): self.pid = pid self.proc_sym = ProcessSymbols(pid) def refresh(self): self.proc_sym.refresh_code_ranges() def __call__(self, addr): return "%s (%x)" % (self.proc_sym.decode_addr(addr), addr)
class StackDecoder(object): def __init__(self, pid): self.pid = pid if pid != -1: self.proc_sym = ProcessSymbols(pid) def refresh(self): if self.pid != -1: self.proc_sym.refresh_code_ranges() def decode_stack(self, info, is_kernel_trace): stack = "" if info.num_frames <= 0: return "???" for i in range(0, info.num_frames): addr = info.callstack[i] if is_kernel_trace: stack += " %s [kernel] (%x) ;" % \ (BPF.ksym(addr), addr) else: stack += " %s (%x) ;" % \ (self.proc_sym.decode_addr(addr), addr) return stack
def __init__(self, pid): self.pid = pid self.proc_sym = ProcessSymbols(pid)
int key = stack_traces.get_stackid(ctx, BPF_F_USER_STACK|BPF_F_REUSE_STACKID); if (key < 0) return 0; u64 zero = 0, *val; val = calls.lookup_or_init(&key, &zero); (*val) += size; return 0; }; """) b.attach_uprobe(name="c", sym="malloc", fn_name="alloc_enter", pid=pid) print("Attaching to malloc in pid %d, Ctrl+C to quit." % pid) decoder = ProcessSymbols(pid) # sleep until Ctrl-C try: sleep(99999999) except KeyboardInterrupt: pass calls = b.get_table("calls") stack_traces = b.get_table("stack_traces") for k, v in reversed(sorted(calls.items(), key=lambda c: c[1].value)): print("%d bytes allocated at:" % v.value) for addr in stack_traces.walk(k.value): print("\t%s (%x)" % (decoder.decode_addr(addr), addr))