1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# ustat Activity stats from high-level languages, including exceptions, 5*387f9dfdSAndroid Build Coastguard Worker# method calls, class loads, garbage collections, and more. 6*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 7*387f9dfdSAndroid Build Coastguard Worker# 8*387f9dfdSAndroid Build Coastguard Worker# USAGE: ustat [-l {java,node,perl,php,python,ruby,tcl}] [-C] 9*387f9dfdSAndroid Build Coastguard Worker# [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] 10*387f9dfdSAndroid Build Coastguard Worker# [interval [count]] 11*387f9dfdSAndroid Build Coastguard Worker# 12*387f9dfdSAndroid Build Coastguard Worker# This uses in-kernel eBPF maps to store per process summaries for efficiency. 13*387f9dfdSAndroid Build Coastguard Worker# Newly-created processes might only be traced at the next interval, if the 14*387f9dfdSAndroid Build Coastguard Worker# relevant USDT probe requires enabling through a semaphore. 15*387f9dfdSAndroid Build Coastguard Worker# 16*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Sasha Goldshtein 17*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 18*387f9dfdSAndroid Build Coastguard Worker# 19*387f9dfdSAndroid Build Coastguard Worker# 26-Oct-2016 Sasha Goldshtein Created this. 20*387f9dfdSAndroid Build Coastguard Worker 21*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 22*387f9dfdSAndroid Build Coastguard Workerimport argparse 23*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, USDT, USDTException 24*387f9dfdSAndroid Build Coastguard Workerimport os 25*387f9dfdSAndroid Build Coastguard Workerimport sys 26*387f9dfdSAndroid Build Coastguard Workerfrom subprocess import call 27*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 28*387f9dfdSAndroid Build Coastguard Worker 29*387f9dfdSAndroid Build Coastguard Workerclass Category(object): 30*387f9dfdSAndroid Build Coastguard Worker THREAD = "THREAD" 31*387f9dfdSAndroid Build Coastguard Worker METHOD = "METHOD" 32*387f9dfdSAndroid Build Coastguard Worker OBJNEW = "OBJNEW" 33*387f9dfdSAndroid Build Coastguard Worker CLOAD = "CLOAD" 34*387f9dfdSAndroid Build Coastguard Worker EXCP = "EXCP" 35*387f9dfdSAndroid Build Coastguard Worker GC = "GC" 36*387f9dfdSAndroid Build Coastguard Worker 37*387f9dfdSAndroid Build Coastguard Workerclass Probe(object): 38*387f9dfdSAndroid Build Coastguard Worker def __init__(self, language, procnames, events): 39*387f9dfdSAndroid Build Coastguard Worker """ 40*387f9dfdSAndroid Build Coastguard Worker Initialize a new probe object with a specific language, set of process 41*387f9dfdSAndroid Build Coastguard Worker names to monitor for that language, and a dictionary of events and 42*387f9dfdSAndroid Build Coastguard Worker categories. The dictionary is a mapping of USDT probe names (such as 43*387f9dfdSAndroid Build Coastguard Worker 'gc__start') to event categories supported by this tool -- from the 44*387f9dfdSAndroid Build Coastguard Worker Category class. 45*387f9dfdSAndroid Build Coastguard Worker """ 46*387f9dfdSAndroid Build Coastguard Worker self.language = language 47*387f9dfdSAndroid Build Coastguard Worker self.procnames = procnames 48*387f9dfdSAndroid Build Coastguard Worker self.events = events 49*387f9dfdSAndroid Build Coastguard Worker 50*387f9dfdSAndroid Build Coastguard Worker def _find_targets(self): 51*387f9dfdSAndroid Build Coastguard Worker """Find pids where the comm is one of the specified list""" 52*387f9dfdSAndroid Build Coastguard Worker self.targets = {} 53*387f9dfdSAndroid Build Coastguard Worker all_pids = [int(pid) for pid in os.listdir('/proc') if pid.isdigit()] 54*387f9dfdSAndroid Build Coastguard Worker for pid in all_pids: 55*387f9dfdSAndroid Build Coastguard Worker try: 56*387f9dfdSAndroid Build Coastguard Worker comm = open('/proc/%d/comm' % pid).read().strip() 57*387f9dfdSAndroid Build Coastguard Worker if comm in self.procnames: 58*387f9dfdSAndroid Build Coastguard Worker cmdline = open('/proc/%d/cmdline' % pid).read() 59*387f9dfdSAndroid Build Coastguard Worker self.targets[pid] = cmdline.replace('\0', ' ') 60*387f9dfdSAndroid Build Coastguard Worker except IOError: 61*387f9dfdSAndroid Build Coastguard Worker continue # process may already have terminated 62*387f9dfdSAndroid Build Coastguard Worker 63*387f9dfdSAndroid Build Coastguard Worker def _enable_probes(self): 64*387f9dfdSAndroid Build Coastguard Worker self.usdts = [] 65*387f9dfdSAndroid Build Coastguard Worker for pid in self.targets: 66*387f9dfdSAndroid Build Coastguard Worker try: 67*387f9dfdSAndroid Build Coastguard Worker usdt = USDT(pid=pid) 68*387f9dfdSAndroid Build Coastguard Worker except USDTException: 69*387f9dfdSAndroid Build Coastguard Worker # avoid race condition on pid going away. 70*387f9dfdSAndroid Build Coastguard Worker print("failed to instrument %d" % pid, file=sys.stderr) 71*387f9dfdSAndroid Build Coastguard Worker continue 72*387f9dfdSAndroid Build Coastguard Worker for event in self.events: 73*387f9dfdSAndroid Build Coastguard Worker try: 74*387f9dfdSAndroid Build Coastguard Worker usdt.enable_probe(event, "%s_%s" % (self.language, event)) 75*387f9dfdSAndroid Build Coastguard Worker except Exception: 76*387f9dfdSAndroid Build Coastguard Worker # This process might not have a recent version of the USDT 77*387f9dfdSAndroid Build Coastguard Worker # probes enabled, or might have been compiled without USDT 78*387f9dfdSAndroid Build Coastguard Worker # probes at all. The process could even have been shut down 79*387f9dfdSAndroid Build Coastguard Worker # and the pid been recycled. We have to gracefully handle 80*387f9dfdSAndroid Build Coastguard Worker # the possibility that we can't attach probes to it at all. 81*387f9dfdSAndroid Build Coastguard Worker pass 82*387f9dfdSAndroid Build Coastguard Worker self.usdts.append(usdt) 83*387f9dfdSAndroid Build Coastguard Worker 84*387f9dfdSAndroid Build Coastguard Worker def _generate_tables(self): 85*387f9dfdSAndroid Build Coastguard Worker text = """ 86*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(%s_%s_counts, u32, u64); // pid to event count 87*387f9dfdSAndroid Build Coastguard Worker """ 88*387f9dfdSAndroid Build Coastguard Worker return str.join('', [text % (self.language, event) 89*387f9dfdSAndroid Build Coastguard Worker for event in self.events]) 90*387f9dfdSAndroid Build Coastguard Worker 91*387f9dfdSAndroid Build Coastguard Worker def _generate_functions(self): 92*387f9dfdSAndroid Build Coastguard Worker text = """ 93*387f9dfdSAndroid Build Coastguard Workerint %s_%s(void *ctx) { 94*387f9dfdSAndroid Build Coastguard Worker u64 *valp, zero = 0; 95*387f9dfdSAndroid Build Coastguard Worker u32 tgid = bpf_get_current_pid_tgid() >> 32; 96*387f9dfdSAndroid Build Coastguard Worker valp = %s_%s_counts.lookup_or_try_init(&tgid, &zero); 97*387f9dfdSAndroid Build Coastguard Worker if (valp) { 98*387f9dfdSAndroid Build Coastguard Worker ++(*valp); 99*387f9dfdSAndroid Build Coastguard Worker } 100*387f9dfdSAndroid Build Coastguard Worker return 0; 101*387f9dfdSAndroid Build Coastguard Worker} 102*387f9dfdSAndroid Build Coastguard Worker """ 103*387f9dfdSAndroid Build Coastguard Worker lang = self.language 104*387f9dfdSAndroid Build Coastguard Worker return str.join('', [text % (lang, event, lang, event) 105*387f9dfdSAndroid Build Coastguard Worker for event in self.events]) 106*387f9dfdSAndroid Build Coastguard Worker 107*387f9dfdSAndroid Build Coastguard Worker def get_program(self): 108*387f9dfdSAndroid Build Coastguard Worker self._find_targets() 109*387f9dfdSAndroid Build Coastguard Worker self._enable_probes() 110*387f9dfdSAndroid Build Coastguard Worker return self._generate_tables() + self._generate_functions() 111*387f9dfdSAndroid Build Coastguard Worker 112*387f9dfdSAndroid Build Coastguard Worker def get_usdts(self): 113*387f9dfdSAndroid Build Coastguard Worker return self.usdts 114*387f9dfdSAndroid Build Coastguard Worker 115*387f9dfdSAndroid Build Coastguard Worker def get_counts(self, bpf): 116*387f9dfdSAndroid Build Coastguard Worker """Return a map of event counts per process""" 117*387f9dfdSAndroid Build Coastguard Worker event_dict = dict([(category, 0) for category in self.events.values()]) 118*387f9dfdSAndroid Build Coastguard Worker result = dict([(pid, event_dict.copy()) for pid in self.targets]) 119*387f9dfdSAndroid Build Coastguard Worker for event, category in self.events.items(): 120*387f9dfdSAndroid Build Coastguard Worker counts = bpf["%s_%s_counts" % (self.language, event)] 121*387f9dfdSAndroid Build Coastguard Worker for pid, count in counts.items(): 122*387f9dfdSAndroid Build Coastguard Worker if pid.value not in result: 123*387f9dfdSAndroid Build Coastguard Worker print("result was not found for %d" % pid.value, file=sys.stderr) 124*387f9dfdSAndroid Build Coastguard Worker continue 125*387f9dfdSAndroid Build Coastguard Worker result[pid.value][category] = count.value 126*387f9dfdSAndroid Build Coastguard Worker counts.clear() 127*387f9dfdSAndroid Build Coastguard Worker return result 128*387f9dfdSAndroid Build Coastguard Worker 129*387f9dfdSAndroid Build Coastguard Worker def cleanup(self): 130*387f9dfdSAndroid Build Coastguard Worker self.usdts = None 131*387f9dfdSAndroid Build Coastguard Worker 132*387f9dfdSAndroid Build Coastguard Workerclass Tool(object): 133*387f9dfdSAndroid Build Coastguard Worker def _parse_args(self): 134*387f9dfdSAndroid Build Coastguard Worker examples = """examples: 135*387f9dfdSAndroid Build Coastguard Worker ./ustat # stats for all languages, 1 second refresh 136*387f9dfdSAndroid Build Coastguard Worker ./ustat -C # don't clear the screen 137*387f9dfdSAndroid Build Coastguard Worker ./ustat -l java # Java processes only 138*387f9dfdSAndroid Build Coastguard Worker ./ustat 5 # 5 second summaries 139*387f9dfdSAndroid Build Coastguard Worker ./ustat 5 10 # 5 second summaries, 10 times only 140*387f9dfdSAndroid Build Coastguard Worker """ 141*387f9dfdSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 142*387f9dfdSAndroid Build Coastguard Worker description="Activity stats from high-level languages.", 143*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 144*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 145*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-l", "--language", 146*387f9dfdSAndroid Build Coastguard Worker choices=["java", "node", "perl", "php", "python", "ruby", "tcl"], 147*387f9dfdSAndroid Build Coastguard Worker help="language to trace (default: all languages)") 148*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-C", "--noclear", action="store_true", 149*387f9dfdSAndroid Build Coastguard Worker help="don't clear the screen") 150*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-S", "--sort", 151*387f9dfdSAndroid Build Coastguard Worker choices=[cat.lower() for cat in dir(Category) if cat.isupper()], 152*387f9dfdSAndroid Build Coastguard Worker help="sort by this field (descending order)") 153*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-r", "--maxrows", default=20, type=int, 154*387f9dfdSAndroid Build Coastguard Worker help="maximum rows to print, default 20") 155*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("-d", "--debug", action="store_true", 156*387f9dfdSAndroid Build Coastguard Worker help="Print the resulting BPF program (for debugging purposes)") 157*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("interval", nargs="?", default=1, type=int, 158*387f9dfdSAndroid Build Coastguard Worker help="output interval, in seconds") 159*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("count", nargs="?", default=99999999, type=int, 160*387f9dfdSAndroid Build Coastguard Worker help="number of outputs") 161*387f9dfdSAndroid Build Coastguard Worker parser.add_argument("--ebpf", action="store_true", 162*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 163*387f9dfdSAndroid Build Coastguard Worker self.args = parser.parse_args() 164*387f9dfdSAndroid Build Coastguard Worker 165*387f9dfdSAndroid Build Coastguard Worker def _create_probes(self): 166*387f9dfdSAndroid Build Coastguard Worker probes_by_lang = { 167*387f9dfdSAndroid Build Coastguard Worker "java": Probe("java", ["java"], { 168*387f9dfdSAndroid Build Coastguard Worker "gc__begin": Category.GC, 169*387f9dfdSAndroid Build Coastguard Worker "mem__pool__gc__begin": Category.GC, 170*387f9dfdSAndroid Build Coastguard Worker "thread__start": Category.THREAD, 171*387f9dfdSAndroid Build Coastguard Worker "class__loaded": Category.CLOAD, 172*387f9dfdSAndroid Build Coastguard Worker "object__alloc": Category.OBJNEW, 173*387f9dfdSAndroid Build Coastguard Worker "method__entry": Category.METHOD, 174*387f9dfdSAndroid Build Coastguard Worker "ExceptionOccurred__entry": Category.EXCP 175*387f9dfdSAndroid Build Coastguard Worker }), 176*387f9dfdSAndroid Build Coastguard Worker "node": Probe("node", ["node"], { 177*387f9dfdSAndroid Build Coastguard Worker "gc__start": Category.GC 178*387f9dfdSAndroid Build Coastguard Worker }), 179*387f9dfdSAndroid Build Coastguard Worker "perl": Probe("perl", ["perl"], { 180*387f9dfdSAndroid Build Coastguard Worker "sub__entry": Category.METHOD 181*387f9dfdSAndroid Build Coastguard Worker }), 182*387f9dfdSAndroid Build Coastguard Worker "php": Probe("php", ["php"], { 183*387f9dfdSAndroid Build Coastguard Worker "function__entry": Category.METHOD, 184*387f9dfdSAndroid Build Coastguard Worker "compile__file__entry": Category.CLOAD, 185*387f9dfdSAndroid Build Coastguard Worker "exception__thrown": Category.EXCP 186*387f9dfdSAndroid Build Coastguard Worker }), 187*387f9dfdSAndroid Build Coastguard Worker "python": Probe("python", ["python"], { 188*387f9dfdSAndroid Build Coastguard Worker "function__entry": Category.METHOD, 189*387f9dfdSAndroid Build Coastguard Worker "gc__start": Category.GC 190*387f9dfdSAndroid Build Coastguard Worker }), 191*387f9dfdSAndroid Build Coastguard Worker "ruby": Probe("ruby", ["ruby", "irb"], { 192*387f9dfdSAndroid Build Coastguard Worker "method__entry": Category.METHOD, 193*387f9dfdSAndroid Build Coastguard Worker "cmethod__entry": Category.METHOD, 194*387f9dfdSAndroid Build Coastguard Worker "gc__mark__begin": Category.GC, 195*387f9dfdSAndroid Build Coastguard Worker "gc__sweep__begin": Category.GC, 196*387f9dfdSAndroid Build Coastguard Worker "object__create": Category.OBJNEW, 197*387f9dfdSAndroid Build Coastguard Worker "hash__create": Category.OBJNEW, 198*387f9dfdSAndroid Build Coastguard Worker "string__create": Category.OBJNEW, 199*387f9dfdSAndroid Build Coastguard Worker "array__create": Category.OBJNEW, 200*387f9dfdSAndroid Build Coastguard Worker "require__entry": Category.CLOAD, 201*387f9dfdSAndroid Build Coastguard Worker "load__entry": Category.CLOAD, 202*387f9dfdSAndroid Build Coastguard Worker "raise": Category.EXCP 203*387f9dfdSAndroid Build Coastguard Worker }), 204*387f9dfdSAndroid Build Coastguard Worker "tcl": Probe("tcl", ["tclsh", "wish"], { 205*387f9dfdSAndroid Build Coastguard Worker "proc__entry": Category.METHOD, 206*387f9dfdSAndroid Build Coastguard Worker "obj__create": Category.OBJNEW 207*387f9dfdSAndroid Build Coastguard Worker }), 208*387f9dfdSAndroid Build Coastguard Worker } 209*387f9dfdSAndroid Build Coastguard Worker 210*387f9dfdSAndroid Build Coastguard Worker if self.args.language: 211*387f9dfdSAndroid Build Coastguard Worker self.probes = [probes_by_lang[self.args.language]] 212*387f9dfdSAndroid Build Coastguard Worker else: 213*387f9dfdSAndroid Build Coastguard Worker self.probes = probes_by_lang.values() 214*387f9dfdSAndroid Build Coastguard Worker 215*387f9dfdSAndroid Build Coastguard Worker def _attach_probes(self): 216*387f9dfdSAndroid Build Coastguard Worker program = str.join('\n', [p.get_program() for p in self.probes]) 217*387f9dfdSAndroid Build Coastguard Worker if self.args.debug or self.args.ebpf: 218*387f9dfdSAndroid Build Coastguard Worker print(program) 219*387f9dfdSAndroid Build Coastguard Worker if self.args.ebpf: 220*387f9dfdSAndroid Build Coastguard Worker exit() 221*387f9dfdSAndroid Build Coastguard Worker for probe in self.probes: 222*387f9dfdSAndroid Build Coastguard Worker print("Attached to %s processes:" % probe.language, 223*387f9dfdSAndroid Build Coastguard Worker str.join(', ', map(str, probe.targets))) 224*387f9dfdSAndroid Build Coastguard Worker self.bpf = BPF(text=program) 225*387f9dfdSAndroid Build Coastguard Worker usdts = [usdt for probe in self.probes for usdt in probe.get_usdts()] 226*387f9dfdSAndroid Build Coastguard Worker # Filter out duplicates when we have multiple processes with the same 227*387f9dfdSAndroid Build Coastguard Worker # uprobe. We are attaching to these probes manually instead of using 228*387f9dfdSAndroid Build Coastguard Worker # the USDT support from the bcc module, because the USDT class attaches 229*387f9dfdSAndroid Build Coastguard Worker # to each uprobe with a specific pid. When there is more than one 230*387f9dfdSAndroid Build Coastguard Worker # process from some language, we end up attaching more than once to the 231*387f9dfdSAndroid Build Coastguard Worker # same uprobe (albeit with different pids), which is not allowed. 232*387f9dfdSAndroid Build Coastguard Worker # Instead, we use a global attach (with pid=-1). 233*387f9dfdSAndroid Build Coastguard Worker uprobes = set([(path, func, addr) for usdt in usdts 234*387f9dfdSAndroid Build Coastguard Worker for (path, func, addr, _) 235*387f9dfdSAndroid Build Coastguard Worker in usdt.enumerate_active_probes()]) 236*387f9dfdSAndroid Build Coastguard Worker for (path, func, addr) in uprobes: 237*387f9dfdSAndroid Build Coastguard Worker self.bpf.attach_uprobe(name=path, fn_name=func, addr=addr, pid=-1) 238*387f9dfdSAndroid Build Coastguard Worker 239*387f9dfdSAndroid Build Coastguard Worker def _detach_probes(self): 240*387f9dfdSAndroid Build Coastguard Worker for probe in self.probes: 241*387f9dfdSAndroid Build Coastguard Worker probe.cleanup() # Cleans up USDT contexts 242*387f9dfdSAndroid Build Coastguard Worker self.bpf.cleanup() # Cleans up all attached probes 243*387f9dfdSAndroid Build Coastguard Worker self.bpf = None 244*387f9dfdSAndroid Build Coastguard Worker 245*387f9dfdSAndroid Build Coastguard Worker def _loop_iter(self): 246*387f9dfdSAndroid Build Coastguard Worker self._attach_probes() 247*387f9dfdSAndroid Build Coastguard Worker try: 248*387f9dfdSAndroid Build Coastguard Worker sleep(self.args.interval) 249*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 250*387f9dfdSAndroid Build Coastguard Worker self.exiting = True 251*387f9dfdSAndroid Build Coastguard Worker 252*387f9dfdSAndroid Build Coastguard Worker if not self.args.noclear: 253*387f9dfdSAndroid Build Coastguard Worker call("clear") 254*387f9dfdSAndroid Build Coastguard Worker else: 255*387f9dfdSAndroid Build Coastguard Worker print() 256*387f9dfdSAndroid Build Coastguard Worker with open("/proc/loadavg") as stats: 257*387f9dfdSAndroid Build Coastguard Worker print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read())) 258*387f9dfdSAndroid Build Coastguard Worker print("%-6s %-20s %-10s %-6s %-10s %-8s %-6s %-6s" % ( 259*387f9dfdSAndroid Build Coastguard Worker "PID", "CMDLINE", "METHOD/s", "GC/s", "OBJNEW/s", 260*387f9dfdSAndroid Build Coastguard Worker "CLOAD/s", "EXC/s", "THR/s")) 261*387f9dfdSAndroid Build Coastguard Worker 262*387f9dfdSAndroid Build Coastguard Worker line = 0 263*387f9dfdSAndroid Build Coastguard Worker counts = {} 264*387f9dfdSAndroid Build Coastguard Worker targets = {} 265*387f9dfdSAndroid Build Coastguard Worker for probe in self.probes: 266*387f9dfdSAndroid Build Coastguard Worker counts.update(probe.get_counts(self.bpf)) 267*387f9dfdSAndroid Build Coastguard Worker targets.update(probe.targets) 268*387f9dfdSAndroid Build Coastguard Worker if self.args.sort: 269*387f9dfdSAndroid Build Coastguard Worker sort_field = self.args.sort.upper() 270*387f9dfdSAndroid Build Coastguard Worker counts = sorted(counts.items(), 271*387f9dfdSAndroid Build Coastguard Worker key=lambda kv: -kv[1].get(sort_field, 0)) 272*387f9dfdSAndroid Build Coastguard Worker else: 273*387f9dfdSAndroid Build Coastguard Worker counts = sorted(counts.items(), key=lambda kv: kv[0]) 274*387f9dfdSAndroid Build Coastguard Worker for pid, stats in counts: 275*387f9dfdSAndroid Build Coastguard Worker print("%-6d %-20s %-10d %-6d %-10d %-8d %-6d %-6d" % ( 276*387f9dfdSAndroid Build Coastguard Worker pid, targets[pid][:20], 277*387f9dfdSAndroid Build Coastguard Worker stats.get(Category.METHOD, 0) / self.args.interval, 278*387f9dfdSAndroid Build Coastguard Worker stats.get(Category.GC, 0) / self.args.interval, 279*387f9dfdSAndroid Build Coastguard Worker stats.get(Category.OBJNEW, 0) / self.args.interval, 280*387f9dfdSAndroid Build Coastguard Worker stats.get(Category.CLOAD, 0) / self.args.interval, 281*387f9dfdSAndroid Build Coastguard Worker stats.get(Category.EXCP, 0) / self.args.interval, 282*387f9dfdSAndroid Build Coastguard Worker stats.get(Category.THREAD, 0) / self.args.interval 283*387f9dfdSAndroid Build Coastguard Worker )) 284*387f9dfdSAndroid Build Coastguard Worker line += 1 285*387f9dfdSAndroid Build Coastguard Worker if line >= self.args.maxrows: 286*387f9dfdSAndroid Build Coastguard Worker break 287*387f9dfdSAndroid Build Coastguard Worker self._detach_probes() 288*387f9dfdSAndroid Build Coastguard Worker 289*387f9dfdSAndroid Build Coastguard Worker def run(self): 290*387f9dfdSAndroid Build Coastguard Worker self._parse_args() 291*387f9dfdSAndroid Build Coastguard Worker self._create_probes() 292*387f9dfdSAndroid Build Coastguard Worker print('Tracing... Output every %d secs. Hit Ctrl-C to end' % 293*387f9dfdSAndroid Build Coastguard Worker self.args.interval) 294*387f9dfdSAndroid Build Coastguard Worker countdown = self.args.count 295*387f9dfdSAndroid Build Coastguard Worker self.exiting = False 296*387f9dfdSAndroid Build Coastguard Worker while True: 297*387f9dfdSAndroid Build Coastguard Worker self._loop_iter() 298*387f9dfdSAndroid Build Coastguard Worker countdown -= 1 299*387f9dfdSAndroid Build Coastguard Worker if self.exiting or countdown == 0: 300*387f9dfdSAndroid Build Coastguard Worker print("Detaching...") 301*387f9dfdSAndroid Build Coastguard Worker exit() 302*387f9dfdSAndroid Build Coastguard Worker 303*387f9dfdSAndroid Build Coastguard Workerif __name__ == "__main__": 304*387f9dfdSAndroid Build Coastguard Worker try: 305*387f9dfdSAndroid Build Coastguard Worker Tool().run() 306*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 307*387f9dfdSAndroid Build Coastguard Worker pass 308