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