1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# funccount Count functions, tracepoints, and USDT probes. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: funccount [-h] [-p PID] [-i INTERVAL] [-d DURATION] [-T] [-r] 8*387f9dfdSAndroid Build Coastguard Worker# [-c CPU] pattern 9*387f9dfdSAndroid Build Coastguard Worker# 10*387f9dfdSAndroid Build Coastguard Worker# The pattern is a string with optional '*' wildcards, similar to file 11*387f9dfdSAndroid Build Coastguard Worker# globbing. If you'd prefer to use regular expressions, use the -r option. 12*387f9dfdSAndroid Build Coastguard Worker# 13*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2015 Brendan Gregg. 14*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 15*387f9dfdSAndroid Build Coastguard Worker# 16*387f9dfdSAndroid Build Coastguard Worker# 09-Sep-2015 Brendan Gregg Created this. 17*387f9dfdSAndroid Build Coastguard Worker# 18-Oct-2016 Sasha Goldshtein Generalized for uprobes, tracepoints, USDT. 18*387f9dfdSAndroid Build Coastguard Worker 19*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 20*387f9dfdSAndroid Build Coastguard Workerfrom bcc import ArgString, BPF, USDT 21*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 22*387f9dfdSAndroid Build Coastguard Workerimport argparse 23*387f9dfdSAndroid Build Coastguard Workerimport re 24*387f9dfdSAndroid Build Coastguard Workerimport signal 25*387f9dfdSAndroid Build Coastguard Workerimport sys 26*387f9dfdSAndroid Build Coastguard Workerimport traceback 27*387f9dfdSAndroid Build Coastguard Worker 28*387f9dfdSAndroid Build Coastguard Workerdebug = False 29*387f9dfdSAndroid Build Coastguard Worker 30*387f9dfdSAndroid Build Coastguard Workerdef verify_limit(num): 31*387f9dfdSAndroid Build Coastguard Worker probe_limit = BPF.get_probe_limit() 32*387f9dfdSAndroid Build Coastguard Worker if num > probe_limit: 33*387f9dfdSAndroid Build Coastguard Worker raise Exception("maximum of %d probes allowed, attempted %d" % 34*387f9dfdSAndroid Build Coastguard Worker (probe_limit, num)) 35*387f9dfdSAndroid Build Coastguard Worker 36*387f9dfdSAndroid Build Coastguard Workerclass Probe(object): 37*387f9dfdSAndroid Build Coastguard Worker def __init__(self, pattern, use_regex=False, pid=None, cpu=None): 38*387f9dfdSAndroid Build Coastguard Worker """Init a new probe. 39*387f9dfdSAndroid Build Coastguard Worker 40*387f9dfdSAndroid Build Coastguard Worker Init the probe from the pattern provided by the user. The supported 41*387f9dfdSAndroid Build Coastguard Worker patterns mimic the 'trace' and 'argdist' tools, but are simpler because 42*387f9dfdSAndroid Build Coastguard Worker we don't have to distinguish between probes and retprobes. 43*387f9dfdSAndroid Build Coastguard Worker 44*387f9dfdSAndroid Build Coastguard Worker func -- probe a kernel function 45*387f9dfdSAndroid Build Coastguard Worker lib:func -- probe a user-space function in the library 'lib' 46*387f9dfdSAndroid Build Coastguard Worker /path:func -- probe a user-space function in binary '/path' 47*387f9dfdSAndroid Build Coastguard Worker p::func -- same thing as 'func' 48*387f9dfdSAndroid Build Coastguard Worker p:lib:func -- same thing as 'lib:func' 49*387f9dfdSAndroid Build Coastguard Worker t:cat:event -- probe a kernel tracepoint 50*387f9dfdSAndroid Build Coastguard Worker u:lib:probe -- probe a USDT tracepoint 51*387f9dfdSAndroid Build Coastguard Worker """ 52*387f9dfdSAndroid Build Coastguard Worker parts = bytes(pattern).split(b':') 53*387f9dfdSAndroid Build Coastguard Worker if len(parts) == 1: 54*387f9dfdSAndroid Build Coastguard Worker parts = [b"p", b"", parts[0]] 55*387f9dfdSAndroid Build Coastguard Worker elif len(parts) == 2: 56*387f9dfdSAndroid Build Coastguard Worker parts = [b"p", parts[0], parts[1]] 57*387f9dfdSAndroid Build Coastguard Worker elif len(parts) == 3: 58*387f9dfdSAndroid Build Coastguard Worker if parts[0] == b"t": 59*387f9dfdSAndroid Build Coastguard Worker parts = [b"t", b"", b"%s:%s" % tuple(parts[1:])] 60*387f9dfdSAndroid Build Coastguard Worker if parts[0] not in [b"p", b"t", b"u"]: 61*387f9dfdSAndroid Build Coastguard Worker raise Exception("Type must be 'p', 't', or 'u', but got %s" % 62*387f9dfdSAndroid Build Coastguard Worker parts[0]) 63*387f9dfdSAndroid Build Coastguard Worker else: 64*387f9dfdSAndroid Build Coastguard Worker raise Exception("Too many ':'-separated components in pattern %s" % 65*387f9dfdSAndroid Build Coastguard Worker pattern) 66*387f9dfdSAndroid Build Coastguard Worker 67*387f9dfdSAndroid Build Coastguard Worker (self.type, self.library, self.pattern) = parts 68*387f9dfdSAndroid Build Coastguard Worker if not use_regex: 69*387f9dfdSAndroid Build Coastguard Worker self.pattern = self.pattern.replace(b'*', b'.*') 70*387f9dfdSAndroid Build Coastguard Worker self.pattern = b'^' + self.pattern + b'$' 71*387f9dfdSAndroid Build Coastguard Worker 72*387f9dfdSAndroid Build Coastguard Worker if (self.type == b"p" and self.library) or self.type == b"u": 73*387f9dfdSAndroid Build Coastguard Worker libpath = BPF.find_library(self.library) 74*387f9dfdSAndroid Build Coastguard Worker if libpath is None: 75*387f9dfdSAndroid Build Coastguard Worker # This might be an executable (e.g. 'bash') 76*387f9dfdSAndroid Build Coastguard Worker libpath = BPF.find_exe(str(self.library)) 77*387f9dfdSAndroid Build Coastguard Worker if libpath is None or len(libpath) == 0: 78*387f9dfdSAndroid Build Coastguard Worker raise Exception("unable to find library %s" % self.library) 79*387f9dfdSAndroid Build Coastguard Worker self.library = libpath 80*387f9dfdSAndroid Build Coastguard Worker 81*387f9dfdSAndroid Build Coastguard Worker self.pid = pid 82*387f9dfdSAndroid Build Coastguard Worker self.cpu = cpu 83*387f9dfdSAndroid Build Coastguard Worker self.matched = 0 84*387f9dfdSAndroid Build Coastguard Worker self.trace_functions = {} # map location number to function name 85*387f9dfdSAndroid Build Coastguard Worker 86*387f9dfdSAndroid Build Coastguard Worker def is_kernel_probe(self): 87*387f9dfdSAndroid Build Coastguard Worker return self.type == b"t" or (self.type == b"p" and self.library == b"") 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard Worker def attach(self): 90*387f9dfdSAndroid Build Coastguard Worker if self.type == b"p" and not self.library: 91*387f9dfdSAndroid Build Coastguard Worker for index, function in self.trace_functions.items(): 92*387f9dfdSAndroid Build Coastguard Worker self.bpf.attach_kprobe( 93*387f9dfdSAndroid Build Coastguard Worker event=function, 94*387f9dfdSAndroid Build Coastguard Worker fn_name="trace_count_%d" % index) 95*387f9dfdSAndroid Build Coastguard Worker elif self.type == b"p" and self.library: 96*387f9dfdSAndroid Build Coastguard Worker for index, function in self.trace_functions.items(): 97*387f9dfdSAndroid Build Coastguard Worker self.bpf.attach_uprobe( 98*387f9dfdSAndroid Build Coastguard Worker name=self.library, 99*387f9dfdSAndroid Build Coastguard Worker sym=function, 100*387f9dfdSAndroid Build Coastguard Worker fn_name="trace_count_%d" % index, 101*387f9dfdSAndroid Build Coastguard Worker pid=self.pid or -1) 102*387f9dfdSAndroid Build Coastguard Worker elif self.type == b"t": 103*387f9dfdSAndroid Build Coastguard Worker for index, function in self.trace_functions.items(): 104*387f9dfdSAndroid Build Coastguard Worker self.bpf.attach_tracepoint( 105*387f9dfdSAndroid Build Coastguard Worker tp=function, 106*387f9dfdSAndroid Build Coastguard Worker fn_name="trace_count_%d" % index) 107*387f9dfdSAndroid Build Coastguard Worker elif self.type == b"u": 108*387f9dfdSAndroid Build Coastguard Worker pass # Nothing to do -- attach already happened in `load` 109*387f9dfdSAndroid Build Coastguard Worker 110*387f9dfdSAndroid Build Coastguard Worker def _add_function(self, template, probe_name): 111*387f9dfdSAndroid Build Coastguard Worker new_func = b"trace_count_%d" % self.matched 112*387f9dfdSAndroid Build Coastguard Worker text = template.replace(b"PROBE_FUNCTION", new_func) 113*387f9dfdSAndroid Build Coastguard Worker text = text.replace(b"LOCATION", b"%d" % self.matched) 114*387f9dfdSAndroid Build Coastguard Worker self.trace_functions[self.matched] = probe_name 115*387f9dfdSAndroid Build Coastguard Worker self.matched += 1 116*387f9dfdSAndroid Build Coastguard Worker return text 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard Worker def _generate_functions(self, template): 119*387f9dfdSAndroid Build Coastguard Worker self.usdt = None 120*387f9dfdSAndroid Build Coastguard Worker text = b"" 121*387f9dfdSAndroid Build Coastguard Worker if self.type == b"p" and not self.library: 122*387f9dfdSAndroid Build Coastguard Worker functions = BPF.get_kprobe_functions(self.pattern) 123*387f9dfdSAndroid Build Coastguard Worker verify_limit(len(functions)) 124*387f9dfdSAndroid Build Coastguard Worker for function in functions: 125*387f9dfdSAndroid Build Coastguard Worker text += self._add_function(template, function) 126*387f9dfdSAndroid Build Coastguard Worker elif self.type == b"p" and self.library: 127*387f9dfdSAndroid Build Coastguard Worker # uprobes are tricky because the same function may have multiple 128*387f9dfdSAndroid Build Coastguard Worker # addresses, and the same address may be mapped to multiple 129*387f9dfdSAndroid Build Coastguard Worker # functions. We aren't allowed to create more than one uprobe 130*387f9dfdSAndroid Build Coastguard Worker # per address, so track unique addresses and ignore functions that 131*387f9dfdSAndroid Build Coastguard Worker # map to an address that we've already seen. Also ignore functions 132*387f9dfdSAndroid Build Coastguard Worker # that may repeat multiple times with different addresses. 133*387f9dfdSAndroid Build Coastguard Worker addresses, functions = (set(), set()) 134*387f9dfdSAndroid Build Coastguard Worker functions_and_addresses = BPF.get_user_functions_and_addresses( 135*387f9dfdSAndroid Build Coastguard Worker self.library, self.pattern) 136*387f9dfdSAndroid Build Coastguard Worker verify_limit(len(functions_and_addresses)) 137*387f9dfdSAndroid Build Coastguard Worker for function, address in functions_and_addresses: 138*387f9dfdSAndroid Build Coastguard Worker if address in addresses or function in functions: 139*387f9dfdSAndroid Build Coastguard Worker continue 140*387f9dfdSAndroid Build Coastguard Worker addresses.add(address) 141*387f9dfdSAndroid Build Coastguard Worker functions.add(function) 142*387f9dfdSAndroid Build Coastguard Worker text += self._add_function(template, function) 143*387f9dfdSAndroid Build Coastguard Worker elif self.type == b"t": 144*387f9dfdSAndroid Build Coastguard Worker tracepoints = BPF.get_tracepoints(self.pattern) 145*387f9dfdSAndroid Build Coastguard Worker verify_limit(len(tracepoints)) 146*387f9dfdSAndroid Build Coastguard Worker for tracepoint in tracepoints: 147*387f9dfdSAndroid Build Coastguard Worker text += self._add_function(template, tracepoint) 148*387f9dfdSAndroid Build Coastguard Worker elif self.type == b"u": 149*387f9dfdSAndroid Build Coastguard Worker self.usdt = USDT(path=str(self.library), pid=self.pid) 150*387f9dfdSAndroid Build Coastguard Worker matches = [] 151*387f9dfdSAndroid Build Coastguard Worker for probe in self.usdt.enumerate_probes(): 152*387f9dfdSAndroid Build Coastguard Worker if not self.pid and (probe.bin_path != self.library): 153*387f9dfdSAndroid Build Coastguard Worker continue 154*387f9dfdSAndroid Build Coastguard Worker if re.match(self.pattern, probe.name): 155*387f9dfdSAndroid Build Coastguard Worker matches.append(probe.name) 156*387f9dfdSAndroid Build Coastguard Worker verify_limit(len(matches)) 157*387f9dfdSAndroid Build Coastguard Worker for match in matches: 158*387f9dfdSAndroid Build Coastguard Worker new_func = b"trace_count_%d" % self.matched 159*387f9dfdSAndroid Build Coastguard Worker text += self._add_function(template, match) 160*387f9dfdSAndroid Build Coastguard Worker self.usdt.enable_probe(match, new_func) 161*387f9dfdSAndroid Build Coastguard Worker if debug: 162*387f9dfdSAndroid Build Coastguard Worker print(self.usdt.get_text()) 163*387f9dfdSAndroid Build Coastguard Worker return text 164*387f9dfdSAndroid Build Coastguard Worker 165*387f9dfdSAndroid Build Coastguard Worker def load(self): 166*387f9dfdSAndroid Build Coastguard Worker trace_count_text = b""" 167*387f9dfdSAndroid Build Coastguard Workerint PROBE_FUNCTION(void *ctx) { 168*387f9dfdSAndroid Build Coastguard Worker FILTERPID 169*387f9dfdSAndroid Build Coastguard Worker FILTERCPU 170*387f9dfdSAndroid Build Coastguard Worker int loc = LOCATION; 171*387f9dfdSAndroid Build Coastguard Worker counts.atomic_increment(loc); 172*387f9dfdSAndroid Build Coastguard Worker return 0; 173*387f9dfdSAndroid Build Coastguard Worker} 174*387f9dfdSAndroid Build Coastguard Worker """ 175*387f9dfdSAndroid Build Coastguard Worker bpf_text = b"""#include <uapi/linux/ptrace.h> 176*387f9dfdSAndroid Build Coastguard Worker 177*387f9dfdSAndroid Build Coastguard WorkerBPF_ARRAY(counts, u64, NUMLOCATIONS); 178*387f9dfdSAndroid Build Coastguard Worker """ 179*387f9dfdSAndroid Build Coastguard Worker 180*387f9dfdSAndroid Build Coastguard Worker # We really mean the tgid from the kernel's perspective, which is in 181*387f9dfdSAndroid Build Coastguard Worker # the top 32 bits of bpf_get_current_pid_tgid(). 182*387f9dfdSAndroid Build Coastguard Worker if self.pid: 183*387f9dfdSAndroid Build Coastguard Worker trace_count_text = trace_count_text.replace(b'FILTERPID', 184*387f9dfdSAndroid Build Coastguard Worker b"""u32 pid = bpf_get_current_pid_tgid() >> 32; 185*387f9dfdSAndroid Build Coastguard Worker if (pid != %d) { return 0; }""" % self.pid) 186*387f9dfdSAndroid Build Coastguard Worker else: 187*387f9dfdSAndroid Build Coastguard Worker trace_count_text = trace_count_text.replace(b'FILTERPID', b'') 188*387f9dfdSAndroid Build Coastguard Worker 189*387f9dfdSAndroid Build Coastguard Worker if self.cpu: 190*387f9dfdSAndroid Build Coastguard Worker trace_count_text = trace_count_text.replace(b'FILTERCPU', 191*387f9dfdSAndroid Build Coastguard Worker b"""u32 cpu = bpf_get_smp_processor_id(); 192*387f9dfdSAndroid Build Coastguard Worker if (cpu != %d) { return 0; }""" % int(self.cpu)) 193*387f9dfdSAndroid Build Coastguard Worker else: 194*387f9dfdSAndroid Build Coastguard Worker trace_count_text = trace_count_text.replace(b'FILTERCPU', b'') 195*387f9dfdSAndroid Build Coastguard Worker 196*387f9dfdSAndroid Build Coastguard Worker bpf_text += self._generate_functions(trace_count_text) 197*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace(b"NUMLOCATIONS", 198*387f9dfdSAndroid Build Coastguard Worker b"%d" % len(self.trace_functions)) 199*387f9dfdSAndroid Build Coastguard Worker if debug: 200*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 201*387f9dfdSAndroid Build Coastguard Worker 202*387f9dfdSAndroid Build Coastguard Worker if self.matched == 0: 203*387f9dfdSAndroid Build Coastguard Worker raise Exception("No functions matched by pattern %s" % 204*387f9dfdSAndroid Build Coastguard Worker self.pattern) 205*387f9dfdSAndroid Build Coastguard Worker 206*387f9dfdSAndroid Build Coastguard Worker self.bpf = BPF(text=bpf_text, 207*387f9dfdSAndroid Build Coastguard Worker usdt_contexts=[self.usdt] if self.usdt else []) 208*387f9dfdSAndroid Build Coastguard Worker self.clear() # Initialize all array items to zero 209*387f9dfdSAndroid Build Coastguard Worker 210*387f9dfdSAndroid Build Coastguard Worker def counts(self): 211*387f9dfdSAndroid Build Coastguard Worker return self.bpf["counts"] 212*387f9dfdSAndroid Build Coastguard Worker 213*387f9dfdSAndroid Build Coastguard Worker def clear(self): 214*387f9dfdSAndroid Build Coastguard Worker counts = self.bpf["counts"] 215*387f9dfdSAndroid Build Coastguard Worker for location, _ in list(self.trace_functions.items()): 216*387f9dfdSAndroid Build Coastguard Worker counts[counts.Key(location)] = counts.Leaf() 217*387f9dfdSAndroid Build Coastguard Worker 218*387f9dfdSAndroid Build Coastguard Workerclass Tool(object): 219*387f9dfdSAndroid Build Coastguard Worker def __init__(self): 220*387f9dfdSAndroid Build Coastguard Worker examples = """examples: 221*387f9dfdSAndroid Build Coastguard Worker ./funccount 'vfs_*' # count kernel fns starting with "vfs" 222*387f9dfdSAndroid Build Coastguard Worker ./funccount -r '^vfs.*' # same as above, using regular expressions 223*387f9dfdSAndroid Build Coastguard Worker ./funccount -Ti 5 'vfs_*' # output every 5 seconds, with timestamps 224*387f9dfdSAndroid Build Coastguard Worker ./funccount -d 10 'vfs_*' # trace for 10 seconds only 225*387f9dfdSAndroid Build Coastguard Worker ./funccount -p 185 'vfs_*' # count vfs calls for PID 181 only 226*387f9dfdSAndroid Build Coastguard Worker ./funccount t:sched:sched_fork # count calls to the sched_fork tracepoint 227*387f9dfdSAndroid Build Coastguard Worker ./funccount -p 185 u:node:gc* # count all GC USDT probes in node, PID 185 228*387f9dfdSAndroid Build Coastguard Worker ./funccount c:malloc # count all malloc() calls in libc 229*387f9dfdSAndroid Build Coastguard Worker ./funccount go:os.* # count all "os.*" calls in libgo 230*387f9dfdSAndroid Build Coastguard Worker ./funccount -p 185 go:os.* # count all "os.*" calls in libgo, PID 185 231*387f9dfdSAndroid Build Coastguard Worker ./funccount ./test:read* # count "read*" calls in the ./test binary 232*387f9dfdSAndroid Build Coastguard Worker ./funccount -c 1 'vfs_*' # count vfs calls on CPU 1 only 233*387f9dfdSAndroid Build Coastguard Worker """ 234*387f9dfdSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 235*387f9dfdSAndroid Build Coastguard Worker description="Count functions, tracepoints, and USDT probes", 236*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 237*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 238*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-p", "--pid", type=int, 239*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 240*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-i", "--interval", 241*387f9dfdSAndroid Build Coastguard Worker help="summary interval, seconds") 242*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-d", "--duration", 243*387f9dfdSAndroid Build Coastguard Worker help="total duration of trace, seconds") 244*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-T", "--timestamp", action="store_true", 245*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output") 246*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-r", "--regexp", action="store_true", 247*387f9dfdSAndroid Build Coastguard Worker help="use regular expressions. Default is \"*\" wildcards only.") 248*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-D", "--debug", action="store_true", 249*387f9dfdSAndroid Build Coastguard Worker help="print BPF program before starting (for debugging purposes)") 250*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-c", "--cpu", 251*387f9dfdSAndroid Build Coastguard Worker help="trace this CPU only") 252*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("pattern", 253*387f9dfdSAndroid Build Coastguard Worker type=ArgString, 254*387f9dfdSAndroid Build Coastguard Worker help="search expression for events") 255*387f9dfdSAndroid Build Coastguard Worker self.args = parser.parse_args() 256*387f9dfdSAndroid Build Coastguard Worker global debug 257*387f9dfdSAndroid Build Coastguard Worker debug = self.args.debug 258*387f9dfdSAndroid Build Coastguard Worker self.probe = Probe(self.args.pattern, self.args.regexp, self.args.pid, 259*387f9dfdSAndroid Build Coastguard Worker self.args.cpu) 260*387f9dfdSAndroid Build Coastguard Worker if self.args.duration and not self.args.interval: 261*387f9dfdSAndroid Build Coastguard Worker self.args.interval = self.args.duration 262*387f9dfdSAndroid Build Coastguard Worker if not self.args.interval: 263*387f9dfdSAndroid Build Coastguard Worker self.args.interval = 99999999 264*387f9dfdSAndroid Build Coastguard Worker 265*387f9dfdSAndroid Build Coastguard Worker @staticmethod 266*387f9dfdSAndroid Build Coastguard Worker def _signal_ignore(signal, frame): 267*387f9dfdSAndroid Build Coastguard Worker print() 268*387f9dfdSAndroid Build Coastguard Worker 269*387f9dfdSAndroid Build Coastguard Worker def run(self): 270*387f9dfdSAndroid Build Coastguard Worker self.probe.load() 271*387f9dfdSAndroid Build Coastguard Worker self.probe.attach() 272*387f9dfdSAndroid Build Coastguard Worker print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." % 273*387f9dfdSAndroid Build Coastguard Worker (self.probe.matched, bytes(self.args.pattern))) 274*387f9dfdSAndroid Build Coastguard Worker exiting = 0 if self.args.interval else 1 275*387f9dfdSAndroid Build Coastguard Worker seconds = 0 276*387f9dfdSAndroid Build Coastguard Worker while True: 277*387f9dfdSAndroid Build Coastguard Worker try: 278*387f9dfdSAndroid Build Coastguard Worker sleep(int(self.args.interval)) 279*387f9dfdSAndroid Build Coastguard Worker seconds += int(self.args.interval) 280*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 281*387f9dfdSAndroid Build Coastguard Worker exiting = 1 282*387f9dfdSAndroid Build Coastguard Worker # as cleanup can take many seconds, trap Ctrl-C: 283*387f9dfdSAndroid Build Coastguard Worker signal.signal(signal.SIGINT, Tool._signal_ignore) 284*387f9dfdSAndroid Build Coastguard Worker if self.args.duration and seconds >= int(self.args.duration): 285*387f9dfdSAndroid Build Coastguard Worker exiting = 1 286*387f9dfdSAndroid Build Coastguard Worker 287*387f9dfdSAndroid Build Coastguard Worker print() 288*387f9dfdSAndroid Build Coastguard Worker if self.args.timestamp: 289*387f9dfdSAndroid Build Coastguard Worker print("%-8s\n" % strftime("%H:%M:%S"), end="") 290*387f9dfdSAndroid Build Coastguard Worker 291*387f9dfdSAndroid Build Coastguard Worker print("%-36s %8s" % ("FUNC", "COUNT")) 292*387f9dfdSAndroid Build Coastguard Worker counts = self.probe.counts() 293*387f9dfdSAndroid Build Coastguard Worker for k, v in sorted(counts.items(), 294*387f9dfdSAndroid Build Coastguard Worker key=lambda counts: counts[1].value): 295*387f9dfdSAndroid Build Coastguard Worker if v.value == 0: 296*387f9dfdSAndroid Build Coastguard Worker continue 297*387f9dfdSAndroid Build Coastguard Worker print("%-36s %8d" % 298*387f9dfdSAndroid Build Coastguard Worker (self.probe.trace_functions[k.value].decode('utf-8', 'replace'), v.value)) 299*387f9dfdSAndroid Build Coastguard Worker 300*387f9dfdSAndroid Build Coastguard Worker if exiting: 301*387f9dfdSAndroid Build Coastguard Worker print("Detaching...") 302*387f9dfdSAndroid Build Coastguard Worker exit() 303*387f9dfdSAndroid Build Coastguard Worker else: 304*387f9dfdSAndroid Build Coastguard Worker self.probe.clear() 305*387f9dfdSAndroid Build Coastguard Worker 306*387f9dfdSAndroid Build Coastguard Workerif __name__ == "__main__": 307*387f9dfdSAndroid Build Coastguard Worker try: 308*387f9dfdSAndroid Build Coastguard Worker Tool().run() 309*387f9dfdSAndroid Build Coastguard Worker except Exception: 310*387f9dfdSAndroid Build Coastguard Worker if debug: 311*387f9dfdSAndroid Build Coastguard Worker traceback.print_exc() 312*387f9dfdSAndroid Build Coastguard Worker elif sys.exc_info()[0] is not SystemExit: 313*387f9dfdSAndroid Build Coastguard Worker print(sys.exc_info()[1]) 314