xref: /aosp_15_r20/external/bcc/tools/offcputime.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# offcputime    Summarize off-CPU time by stack trace
4*387f9dfdSAndroid Build Coastguard Worker#               For Linux, uses BCC, eBPF.
5*387f9dfdSAndroid Build Coastguard Worker#
6*387f9dfdSAndroid Build Coastguard Worker# USAGE: offcputime [-h] [-p PID | -t TID | -u | -k] [-U | -K] [-d] [-f] [-s]
7*387f9dfdSAndroid Build Coastguard Worker#                   [--stack-storage-size STACK_STORAGE_SIZE]
8*387f9dfdSAndroid Build Coastguard Worker#                   [-m MIN_BLOCK_TIME] [-M MAX_BLOCK_TIME] [--state STATE]
9*387f9dfdSAndroid Build Coastguard Worker#                   [duration]
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
12*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
13*387f9dfdSAndroid Build Coastguard Worker#
14*387f9dfdSAndroid Build Coastguard Worker# 13-Jan-2016	Brendan Gregg	Created this.
15*387f9dfdSAndroid Build Coastguard Worker# 27-Mar-2023	Rocky Xing      Added option to show symbol offsets.
16*387f9dfdSAndroid Build Coastguard Worker# 04-Apr-2023   Rocky Xing      Updated default stack storage size.
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
19*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
20*387f9dfdSAndroid Build Coastguard Workerfrom sys import stderr
21*387f9dfdSAndroid Build Coastguard Workerimport argparse
22*387f9dfdSAndroid Build Coastguard Workerimport errno
23*387f9dfdSAndroid Build Coastguard Workerimport signal
24*387f9dfdSAndroid Build Coastguard Worker
25*387f9dfdSAndroid Build Coastguard Worker# arg validation
26*387f9dfdSAndroid Build Coastguard Workerdef positive_int(val):
27*387f9dfdSAndroid Build Coastguard Worker    try:
28*387f9dfdSAndroid Build Coastguard Worker        ival = int(val)
29*387f9dfdSAndroid Build Coastguard Worker    except ValueError:
30*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be an integer")
31*387f9dfdSAndroid Build Coastguard Worker
32*387f9dfdSAndroid Build Coastguard Worker    if ival < 0:
33*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be positive")
34*387f9dfdSAndroid Build Coastguard Worker    return ival
35*387f9dfdSAndroid Build Coastguard Worker
36*387f9dfdSAndroid Build Coastguard Workerdef positive_nonzero_int(val):
37*387f9dfdSAndroid Build Coastguard Worker    ival = positive_int(val)
38*387f9dfdSAndroid Build Coastguard Worker    if ival == 0:
39*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be nonzero")
40*387f9dfdSAndroid Build Coastguard Worker    return ival
41*387f9dfdSAndroid Build Coastguard Worker
42*387f9dfdSAndroid Build Coastguard Workerdef stack_id_err(stack_id):
43*387f9dfdSAndroid Build Coastguard Worker    # -EFAULT in get_stackid normally means the stack-trace is not available,
44*387f9dfdSAndroid Build Coastguard Worker    # Such as getting kernel stack trace in userspace code
45*387f9dfdSAndroid Build Coastguard Worker    return (stack_id < 0) and (stack_id != -errno.EFAULT)
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker# arguments
48*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
49*387f9dfdSAndroid Build Coastguard Worker    ./offcputime             # trace off-CPU stack time until Ctrl-C
50*387f9dfdSAndroid Build Coastguard Worker    ./offcputime 5           # trace for 5 seconds only
51*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -f 5        # 5 seconds, and output in folded format
52*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -s 5        # 5 seconds, and show symbol offsets
53*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -m 1000     # trace only events that last more than 1000 usec
54*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -M 10000    # trace only events that last less than 10000 usec
55*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -p 185      # only trace threads for PID 185
56*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -t 188      # only trace thread 188
57*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -u          # only trace user threads (no kernel)
58*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -k          # only trace kernel threads (no user)
59*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -U          # only show user space stacks (no kernel)
60*387f9dfdSAndroid Build Coastguard Worker    ./offcputime -K          # only show kernel space stacks (no user)
61*387f9dfdSAndroid Build Coastguard Worker"""
62*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
63*387f9dfdSAndroid Build Coastguard Worker    description="Summarize off-CPU time by stack trace",
64*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
65*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
66*387f9dfdSAndroid Build Coastguard Workerthread_group = parser.add_mutually_exclusive_group()
67*387f9dfdSAndroid Build Coastguard Worker# Note: this script provides --pid and --tid flags but their arguments are
68*387f9dfdSAndroid Build Coastguard Worker# referred to internally using kernel nomenclature: TGID and PID.
69*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-p", "--pid", metavar="PID", dest="tgid",
70*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only", type=positive_int)
71*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-t", "--tid", metavar="TID", dest="pid",
72*387f9dfdSAndroid Build Coastguard Worker    help="trace this TID only", type=positive_int)
73*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-u", "--user-threads-only", action="store_true",
74*387f9dfdSAndroid Build Coastguard Worker    help="user threads only (no kernel threads)")
75*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-k", "--kernel-threads-only", action="store_true",
76*387f9dfdSAndroid Build Coastguard Worker    help="kernel threads only (no user threads)")
77*387f9dfdSAndroid Build Coastguard Workerstack_group = parser.add_mutually_exclusive_group()
78*387f9dfdSAndroid Build Coastguard Workerstack_group.add_argument("-U", "--user-stacks-only", action="store_true",
79*387f9dfdSAndroid Build Coastguard Worker    help="show stacks from user space only (no kernel space stacks)")
80*387f9dfdSAndroid Build Coastguard Workerstack_group.add_argument("-K", "--kernel-stacks-only", action="store_true",
81*387f9dfdSAndroid Build Coastguard Worker    help="show stacks from kernel space only (no user space stacks)")
82*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--delimited", action="store_true",
83*387f9dfdSAndroid Build Coastguard Worker    help="insert delimiter between kernel/user stacks")
84*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-f", "--folded", action="store_true",
85*387f9dfdSAndroid Build Coastguard Worker    help="output folded format")
86*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--offset", action="store_true",
87*387f9dfdSAndroid Build Coastguard Worker    help="show address offsets")
88*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--stack-storage-size", default=16384,
89*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
90*387f9dfdSAndroid Build Coastguard Worker    help="the number of unique stack traces that can be stored and "
91*387f9dfdSAndroid Build Coastguard Worker         "displayed (default 16384)")
92*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("duration", nargs="?", default=99999999,
93*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
94*387f9dfdSAndroid Build Coastguard Worker    help="duration of trace, in seconds")
95*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-m", "--min-block-time", default=1,
96*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
97*387f9dfdSAndroid Build Coastguard Worker    help="the amount of time in microseconds over which we " +
98*387f9dfdSAndroid Build Coastguard Worker         "store traces (default 1)")
99*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-M", "--max-block-time", default=(1 << 64) - 1,
100*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
101*387f9dfdSAndroid Build Coastguard Worker    help="the amount of time in microseconds under which we " +
102*387f9dfdSAndroid Build Coastguard Worker         "store traces (default U64_MAX)")
103*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--state", type=positive_int,
104*387f9dfdSAndroid Build Coastguard Worker    help="filter on this thread state bitmask (eg, 2 == TASK_UNINTERRUPTIBLE" +
105*387f9dfdSAndroid Build Coastguard Worker         ") see include/linux/sched.h")
106*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
107*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
108*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
109*387f9dfdSAndroid Build Coastguard Workerfolded = args.folded
110*387f9dfdSAndroid Build Coastguard Workerduration = int(args.duration)
111*387f9dfdSAndroid Build Coastguard Workerdebug = 0
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Workerif args.folded and args.offset:
114*387f9dfdSAndroid Build Coastguard Worker    print("ERROR: can only use -f or -s. Exiting.")
115*387f9dfdSAndroid Build Coastguard Worker    exit()
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Worker# signal handler
118*387f9dfdSAndroid Build Coastguard Workerdef signal_ignore(signal, frame):
119*387f9dfdSAndroid Build Coastguard Worker    print()
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker# define BPF program
122*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
123*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
124*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Worker#define MINBLOCK_US    MINBLOCK_US_VALUEULL
127*387f9dfdSAndroid Build Coastguard Worker#define MAXBLOCK_US    MAXBLOCK_US_VALUEULL
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Workerstruct key_t {
130*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
131*387f9dfdSAndroid Build Coastguard Worker    u32 tgid;
132*387f9dfdSAndroid Build Coastguard Worker    int user_stack_id;
133*387f9dfdSAndroid Build Coastguard Worker    int kernel_stack_id;
134*387f9dfdSAndroid Build Coastguard Worker    char name[TASK_COMM_LEN];
135*387f9dfdSAndroid Build Coastguard Worker};
136*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(counts, struct key_t);
137*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, u32);
138*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, STACK_STORAGE_SIZE);
139*387f9dfdSAndroid Build Coastguard Worker
140*387f9dfdSAndroid Build Coastguard Workerstruct warn_event_t {
141*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
142*387f9dfdSAndroid Build Coastguard Worker    u32 tgid;
143*387f9dfdSAndroid Build Coastguard Worker    u32 t_start;
144*387f9dfdSAndroid Build Coastguard Worker    u32 t_end;
145*387f9dfdSAndroid Build Coastguard Worker};
146*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(warn_events);
147*387f9dfdSAndroid Build Coastguard Worker
148*387f9dfdSAndroid Build Coastguard Workerint oncpu(struct pt_regs *ctx, struct task_struct *prev) {
149*387f9dfdSAndroid Build Coastguard Worker    u32 pid = prev->pid;
150*387f9dfdSAndroid Build Coastguard Worker    u32 tgid = prev->tgid;
151*387f9dfdSAndroid Build Coastguard Worker    u64 ts, *tsp;
152*387f9dfdSAndroid Build Coastguard Worker
153*387f9dfdSAndroid Build Coastguard Worker    // record previous thread sleep time
154*387f9dfdSAndroid Build Coastguard Worker    if ((THREAD_FILTER) && (STATE_FILTER)) {
155*387f9dfdSAndroid Build Coastguard Worker        ts = bpf_ktime_get_ns();
156*387f9dfdSAndroid Build Coastguard Worker        start.update(&pid, &ts);
157*387f9dfdSAndroid Build Coastguard Worker    }
158*387f9dfdSAndroid Build Coastguard Worker
159*387f9dfdSAndroid Build Coastguard Worker    // get the current thread's start time
160*387f9dfdSAndroid Build Coastguard Worker    pid = bpf_get_current_pid_tgid();
161*387f9dfdSAndroid Build Coastguard Worker    tgid = bpf_get_current_pid_tgid() >> 32;
162*387f9dfdSAndroid Build Coastguard Worker    tsp = start.lookup(&pid);
163*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0) {
164*387f9dfdSAndroid Build Coastguard Worker        return 0;        // missed start or filtered
165*387f9dfdSAndroid Build Coastguard Worker    }
166*387f9dfdSAndroid Build Coastguard Worker
167*387f9dfdSAndroid Build Coastguard Worker    // calculate current thread's delta time
168*387f9dfdSAndroid Build Coastguard Worker    u64 t_start = *tsp;
169*387f9dfdSAndroid Build Coastguard Worker    u64 t_end = bpf_ktime_get_ns();
170*387f9dfdSAndroid Build Coastguard Worker    start.delete(&pid);
171*387f9dfdSAndroid Build Coastguard Worker    if (t_start > t_end) {
172*387f9dfdSAndroid Build Coastguard Worker        struct warn_event_t event = {
173*387f9dfdSAndroid Build Coastguard Worker            .pid = pid,
174*387f9dfdSAndroid Build Coastguard Worker            .tgid = tgid,
175*387f9dfdSAndroid Build Coastguard Worker            .t_start = t_start,
176*387f9dfdSAndroid Build Coastguard Worker            .t_end = t_end,
177*387f9dfdSAndroid Build Coastguard Worker        };
178*387f9dfdSAndroid Build Coastguard Worker        warn_events.perf_submit(ctx, &event, sizeof(event));
179*387f9dfdSAndroid Build Coastguard Worker        return 0;
180*387f9dfdSAndroid Build Coastguard Worker    }
181*387f9dfdSAndroid Build Coastguard Worker    u64 delta = t_end - t_start;
182*387f9dfdSAndroid Build Coastguard Worker    delta = delta / 1000;
183*387f9dfdSAndroid Build Coastguard Worker    if ((delta < MINBLOCK_US) || (delta > MAXBLOCK_US)) {
184*387f9dfdSAndroid Build Coastguard Worker        return 0;
185*387f9dfdSAndroid Build Coastguard Worker    }
186*387f9dfdSAndroid Build Coastguard Worker
187*387f9dfdSAndroid Build Coastguard Worker    // create map key
188*387f9dfdSAndroid Build Coastguard Worker    struct key_t key = {};
189*387f9dfdSAndroid Build Coastguard Worker
190*387f9dfdSAndroid Build Coastguard Worker    key.pid = pid;
191*387f9dfdSAndroid Build Coastguard Worker    key.tgid = tgid;
192*387f9dfdSAndroid Build Coastguard Worker    key.user_stack_id = USER_STACK_GET;
193*387f9dfdSAndroid Build Coastguard Worker    key.kernel_stack_id = KERNEL_STACK_GET;
194*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&key.name, sizeof(key.name));
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Worker    counts.increment(key, delta);
197*387f9dfdSAndroid Build Coastguard Worker    return 0;
198*387f9dfdSAndroid Build Coastguard Worker}
199*387f9dfdSAndroid Build Coastguard Worker"""
200*387f9dfdSAndroid Build Coastguard Worker
201*387f9dfdSAndroid Build Coastguard Worker# set thread filter
202*387f9dfdSAndroid Build Coastguard Workerthread_context = ""
203*387f9dfdSAndroid Build Coastguard Workerif args.tgid is not None:
204*387f9dfdSAndroid Build Coastguard Worker    thread_context = "PID %d" % args.tgid
205*387f9dfdSAndroid Build Coastguard Worker    thread_filter = 'tgid == %d' % args.tgid
206*387f9dfdSAndroid Build Coastguard Workerelif args.pid is not None:
207*387f9dfdSAndroid Build Coastguard Worker    thread_context = "TID %d" % args.pid
208*387f9dfdSAndroid Build Coastguard Worker    thread_filter = 'pid == %d' % args.pid
209*387f9dfdSAndroid Build Coastguard Workerelif args.user_threads_only:
210*387f9dfdSAndroid Build Coastguard Worker    thread_context = "user threads"
211*387f9dfdSAndroid Build Coastguard Worker    thread_filter = '!(prev->flags & PF_KTHREAD)'
212*387f9dfdSAndroid Build Coastguard Workerelif args.kernel_threads_only:
213*387f9dfdSAndroid Build Coastguard Worker    thread_context = "kernel threads"
214*387f9dfdSAndroid Build Coastguard Worker    thread_filter = 'prev->flags & PF_KTHREAD'
215*387f9dfdSAndroid Build Coastguard Workerelse:
216*387f9dfdSAndroid Build Coastguard Worker    thread_context = "all threads"
217*387f9dfdSAndroid Build Coastguard Worker    thread_filter = '1'
218*387f9dfdSAndroid Build Coastguard Workerif args.state == 0:
219*387f9dfdSAndroid Build Coastguard Worker    state_filter = 'prev->STATE_FIELD == 0'
220*387f9dfdSAndroid Build Coastguard Workerelif args.state:
221*387f9dfdSAndroid Build Coastguard Worker    # these states are sometimes bitmask checked
222*387f9dfdSAndroid Build Coastguard Worker    state_filter = 'prev->STATE_FIELD & %d' % args.state
223*387f9dfdSAndroid Build Coastguard Workerelse:
224*387f9dfdSAndroid Build Coastguard Worker    state_filter = '1'
225*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('THREAD_FILTER', thread_filter)
226*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('STATE_FILTER', state_filter)
227*387f9dfdSAndroid Build Coastguard Workerif BPF.kernel_struct_has_field(b'task_struct', b'__state') == 1:
228*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('STATE_FIELD', '__state')
229*387f9dfdSAndroid Build Coastguard Workerelse:
230*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('STATE_FIELD', 'state')
231*387f9dfdSAndroid Build Coastguard Worker
232*387f9dfdSAndroid Build Coastguard Worker# set stack storage size
233*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('STACK_STORAGE_SIZE', str(args.stack_storage_size))
234*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('MINBLOCK_US_VALUE', str(args.min_block_time))
235*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('MAXBLOCK_US_VALUE', str(args.max_block_time))
236*387f9dfdSAndroid Build Coastguard Worker
237*387f9dfdSAndroid Build Coastguard Worker# handle stack args
238*387f9dfdSAndroid Build Coastguard Workerkernel_stack_get = "stack_traces.get_stackid(ctx, 0)"
239*387f9dfdSAndroid Build Coastguard Workeruser_stack_get = "stack_traces.get_stackid(ctx, BPF_F_USER_STACK)"
240*387f9dfdSAndroid Build Coastguard Workerstack_context = ""
241*387f9dfdSAndroid Build Coastguard Workerif args.user_stacks_only:
242*387f9dfdSAndroid Build Coastguard Worker    stack_context = "user"
243*387f9dfdSAndroid Build Coastguard Worker    kernel_stack_get = "-1"
244*387f9dfdSAndroid Build Coastguard Workerelif args.kernel_stacks_only:
245*387f9dfdSAndroid Build Coastguard Worker    stack_context = "kernel"
246*387f9dfdSAndroid Build Coastguard Worker    user_stack_get = "-1"
247*387f9dfdSAndroid Build Coastguard Workerelse:
248*387f9dfdSAndroid Build Coastguard Worker    stack_context = "user + kernel"
249*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('USER_STACK_GET', user_stack_get)
250*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('KERNEL_STACK_GET', kernel_stack_get)
251*387f9dfdSAndroid Build Coastguard Worker
252*387f9dfdSAndroid Build Coastguard Workerneed_delimiter = args.delimited and not (args.kernel_stacks_only or
253*387f9dfdSAndroid Build Coastguard Worker                                         args.user_stacks_only)
254*387f9dfdSAndroid Build Coastguard Worker
255*387f9dfdSAndroid Build Coastguard Worker# check for an edge case; the code below will handle this case correctly
256*387f9dfdSAndroid Build Coastguard Worker# but ultimately nothing will be displayed
257*387f9dfdSAndroid Build Coastguard Workerif args.kernel_threads_only and args.user_stacks_only:
258*387f9dfdSAndroid Build Coastguard Worker    print("ERROR: Displaying user stacks for kernel threads " +
259*387f9dfdSAndroid Build Coastguard Worker          "doesn't make sense.", file=stderr)
260*387f9dfdSAndroid Build Coastguard Worker    exit(2)
261*387f9dfdSAndroid Build Coastguard Worker
262*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
263*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
264*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
265*387f9dfdSAndroid Build Coastguard Worker        print("ERROR: Exiting")
266*387f9dfdSAndroid Build Coastguard Worker        exit(3)
267*387f9dfdSAndroid Build Coastguard Worker
268*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
269*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
270*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event_re="^finish_task_switch$|^finish_task_switch\.isra\.\d$",
271*387f9dfdSAndroid Build Coastguard Worker                fn_name="oncpu")
272*387f9dfdSAndroid Build Coastguard Workermatched = b.num_open_kprobes()
273*387f9dfdSAndroid Build Coastguard Workerif matched == 0:
274*387f9dfdSAndroid Build Coastguard Worker    print("error: 0 functions traced. Exiting.", file=stderr)
275*387f9dfdSAndroid Build Coastguard Worker    exit(4)
276*387f9dfdSAndroid Build Coastguard Worker
277*387f9dfdSAndroid Build Coastguard Worker# header
278*387f9dfdSAndroid Build Coastguard Workerif not folded:
279*387f9dfdSAndroid Build Coastguard Worker    print("Tracing off-CPU time (us) of %s by %s stack" %
280*387f9dfdSAndroid Build Coastguard Worker        (thread_context, stack_context), end="")
281*387f9dfdSAndroid Build Coastguard Worker    if duration < 99999999:
282*387f9dfdSAndroid Build Coastguard Worker        print(" for %d secs." % duration)
283*387f9dfdSAndroid Build Coastguard Worker    else:
284*387f9dfdSAndroid Build Coastguard Worker        print("... Hit Ctrl-C to end.")
285*387f9dfdSAndroid Build Coastguard Worker
286*387f9dfdSAndroid Build Coastguard Worker
287*387f9dfdSAndroid Build Coastguard Workerdef print_warn_event(cpu, data, size):
288*387f9dfdSAndroid Build Coastguard Worker    event = b["warn_events"].event(data)
289*387f9dfdSAndroid Build Coastguard Worker    # See https://github.com/iovisor/bcc/pull/3227 for those wondering how can this happen.
290*387f9dfdSAndroid Build Coastguard Worker    print("WARN: Skipped an event with negative duration: pid:%d, tgid:%d, off-cpu:%d, on-cpu:%d"
291*387f9dfdSAndroid Build Coastguard Worker          % (event.pid, event.tgid, event.t_start, event.t_end),
292*387f9dfdSAndroid Build Coastguard Worker          file=stderr)
293*387f9dfdSAndroid Build Coastguard Worker
294*387f9dfdSAndroid Build Coastguard Workerb["warn_events"].open_perf_buffer(print_warn_event)
295*387f9dfdSAndroid Build Coastguard Workertry:
296*387f9dfdSAndroid Build Coastguard Worker    duration_ms = duration * 1000
297*387f9dfdSAndroid Build Coastguard Worker    start_time_ms = int(BPF.monotonic_time() / 1000000)
298*387f9dfdSAndroid Build Coastguard Worker    while True:
299*387f9dfdSAndroid Build Coastguard Worker        elapsed_ms = int(BPF.monotonic_time() / 1000000) - start_time_ms
300*387f9dfdSAndroid Build Coastguard Worker        if elapsed_ms >= duration_ms:
301*387f9dfdSAndroid Build Coastguard Worker            break
302*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll(timeout=duration_ms - elapsed_ms)
303*387f9dfdSAndroid Build Coastguard Workerexcept KeyboardInterrupt:
304*387f9dfdSAndroid Build Coastguard Worker    # as cleanup can take many seconds, trap Ctrl-C:
305*387f9dfdSAndroid Build Coastguard Worker    signal.signal(signal.SIGINT, signal_ignore)
306*387f9dfdSAndroid Build Coastguard Worker
307*387f9dfdSAndroid Build Coastguard Workerif not folded:
308*387f9dfdSAndroid Build Coastguard Worker    print()
309*387f9dfdSAndroid Build Coastguard Worker
310*387f9dfdSAndroid Build Coastguard Workershow_offset = False
311*387f9dfdSAndroid Build Coastguard Workerif args.offset:
312*387f9dfdSAndroid Build Coastguard Worker    show_offset = True
313*387f9dfdSAndroid Build Coastguard Worker
314*387f9dfdSAndroid Build Coastguard Workermissing_stacks = 0
315*387f9dfdSAndroid Build Coastguard Workerhas_enomem = False
316*387f9dfdSAndroid Build Coastguard Workercounts = b.get_table("counts")
317*387f9dfdSAndroid Build Coastguard Workerstack_traces = b.get_table("stack_traces")
318*387f9dfdSAndroid Build Coastguard Workerfor k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
319*387f9dfdSAndroid Build Coastguard Worker    # handle get_stackid errors
320*387f9dfdSAndroid Build Coastguard Worker    if not args.user_stacks_only and stack_id_err(k.kernel_stack_id):
321*387f9dfdSAndroid Build Coastguard Worker        missing_stacks += 1
322*387f9dfdSAndroid Build Coastguard Worker        has_enomem = has_enomem or k.kernel_stack_id == -errno.ENOMEM
323*387f9dfdSAndroid Build Coastguard Worker    if not args.kernel_stacks_only and stack_id_err(k.user_stack_id):
324*387f9dfdSAndroid Build Coastguard Worker        missing_stacks += 1
325*387f9dfdSAndroid Build Coastguard Worker        has_enomem = has_enomem or k.user_stack_id == -errno.ENOMEM
326*387f9dfdSAndroid Build Coastguard Worker
327*387f9dfdSAndroid Build Coastguard Worker    # user stacks will be symbolized by tgid, not pid, to avoid the overhead
328*387f9dfdSAndroid Build Coastguard Worker    # of one symbol resolver per thread
329*387f9dfdSAndroid Build Coastguard Worker    user_stack = [] if k.user_stack_id < 0 else \
330*387f9dfdSAndroid Build Coastguard Worker        stack_traces.walk(k.user_stack_id)
331*387f9dfdSAndroid Build Coastguard Worker    kernel_stack = [] if k.kernel_stack_id < 0 else \
332*387f9dfdSAndroid Build Coastguard Worker        stack_traces.walk(k.kernel_stack_id)
333*387f9dfdSAndroid Build Coastguard Worker
334*387f9dfdSAndroid Build Coastguard Worker    if folded:
335*387f9dfdSAndroid Build Coastguard Worker        # print folded stack output
336*387f9dfdSAndroid Build Coastguard Worker        user_stack = list(user_stack)
337*387f9dfdSAndroid Build Coastguard Worker        kernel_stack = list(kernel_stack)
338*387f9dfdSAndroid Build Coastguard Worker        line = [k.name.decode('utf-8', 'replace')]
339*387f9dfdSAndroid Build Coastguard Worker        # if we failed to get the stack is, such as due to no space (-ENOMEM) or
340*387f9dfdSAndroid Build Coastguard Worker        # hash collision (-EEXIST), we still print a placeholder for consistency
341*387f9dfdSAndroid Build Coastguard Worker        if not args.kernel_stacks_only:
342*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.user_stack_id):
343*387f9dfdSAndroid Build Coastguard Worker                line.append("[Missed User Stack]")
344*387f9dfdSAndroid Build Coastguard Worker            else:
345*387f9dfdSAndroid Build Coastguard Worker                line.extend([b.sym(addr, k.tgid).decode('utf-8', 'replace')
346*387f9dfdSAndroid Build Coastguard Worker                    for addr in reversed(user_stack)])
347*387f9dfdSAndroid Build Coastguard Worker        if not args.user_stacks_only:
348*387f9dfdSAndroid Build Coastguard Worker            line.extend(["-"] if (need_delimiter and k.kernel_stack_id >= 0 and k.user_stack_id >= 0) else [])
349*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.kernel_stack_id):
350*387f9dfdSAndroid Build Coastguard Worker                line.append("[Missed Kernel Stack]")
351*387f9dfdSAndroid Build Coastguard Worker            else:
352*387f9dfdSAndroid Build Coastguard Worker                line.extend([b.ksym(addr).decode('utf-8', 'replace')
353*387f9dfdSAndroid Build Coastguard Worker                    for addr in reversed(kernel_stack)])
354*387f9dfdSAndroid Build Coastguard Worker        print("%s %d" % (";".join(line), v.value))
355*387f9dfdSAndroid Build Coastguard Worker    else:
356*387f9dfdSAndroid Build Coastguard Worker        # print default multi-line stack output
357*387f9dfdSAndroid Build Coastguard Worker        if not args.user_stacks_only:
358*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.kernel_stack_id):
359*387f9dfdSAndroid Build Coastguard Worker                print("    [Missed Kernel Stack]")
360*387f9dfdSAndroid Build Coastguard Worker            else:
361*387f9dfdSAndroid Build Coastguard Worker                for addr in kernel_stack:
362*387f9dfdSAndroid Build Coastguard Worker                    print("    %s" % b.ksym(addr, show_offset=show_offset).decode('utf-8', 'replace'))
363*387f9dfdSAndroid Build Coastguard Worker        if not args.kernel_stacks_only:
364*387f9dfdSAndroid Build Coastguard Worker            if need_delimiter and k.user_stack_id >= 0 and k.kernel_stack_id >= 0:
365*387f9dfdSAndroid Build Coastguard Worker                print("    --")
366*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.user_stack_id):
367*387f9dfdSAndroid Build Coastguard Worker                print("    [Missed User Stack]")
368*387f9dfdSAndroid Build Coastguard Worker            else:
369*387f9dfdSAndroid Build Coastguard Worker                for addr in user_stack:
370*387f9dfdSAndroid Build Coastguard Worker                    print("    %s" % b.sym(addr, k.tgid, show_offset=show_offset).decode('utf-8', 'replace'))
371*387f9dfdSAndroid Build Coastguard Worker        print("    %-16s %s (%d)" % ("-", k.name.decode('utf-8', 'replace'), k.pid))
372*387f9dfdSAndroid Build Coastguard Worker        print("        %d\n" % v.value)
373*387f9dfdSAndroid Build Coastguard Worker
374*387f9dfdSAndroid Build Coastguard Workerif missing_stacks > 0:
375*387f9dfdSAndroid Build Coastguard Worker    enomem_str = "" if not has_enomem else \
376*387f9dfdSAndroid Build Coastguard Worker        " Consider increasing --stack-storage-size."
377*387f9dfdSAndroid Build Coastguard Worker    print("WARNING: %d stack traces lost and could not be displayed.%s" %
378*387f9dfdSAndroid Build Coastguard Worker        (missing_stacks, enomem_str),
379*387f9dfdSAndroid Build Coastguard Worker        file=stderr)
380