xref: /aosp_15_r20/external/bcc/tools/lib/ustat.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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