xref: /aosp_15_r20/external/bcc/tools/offwaketime.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# offwaketime   Summarize blocked time by kernel off-CPU stack + waker stack
4*387f9dfdSAndroid Build Coastguard Worker#               For Linux, uses BCC, eBPF.
5*387f9dfdSAndroid Build Coastguard Worker#
6*387f9dfdSAndroid Build Coastguard Worker# USAGE: offwaketime [-h] [-p PID | -u | -k] [-U | -K] [-f] [duration]
7*387f9dfdSAndroid Build Coastguard Worker#
8*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
9*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# 20-Jan-2016   Brendan Gregg   Created this.
12*387f9dfdSAndroid Build Coastguard Worker# 04-Apr-2023   Rocky Xing      Updated default stack storage size.
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
15*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
16*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep
17*387f9dfdSAndroid Build Coastguard Workerimport argparse
18*387f9dfdSAndroid Build Coastguard Workerimport signal
19*387f9dfdSAndroid Build Coastguard Workerimport errno
20*387f9dfdSAndroid Build Coastguard Workerfrom sys import stderr
21*387f9dfdSAndroid Build Coastguard Worker
22*387f9dfdSAndroid Build Coastguard Worker# arg validation
23*387f9dfdSAndroid Build Coastguard Workerdef positive_int(val):
24*387f9dfdSAndroid Build Coastguard Worker    dest = []
25*387f9dfdSAndroid Build Coastguard Worker    # Filter up to 5 pids, arbitrary
26*387f9dfdSAndroid Build Coastguard Worker    args_list = val.split(",", 5)
27*387f9dfdSAndroid Build Coastguard Worker    pids_to_add = min(len(args_list), 5)
28*387f9dfdSAndroid Build Coastguard Worker    for i in range(pids_to_add):
29*387f9dfdSAndroid Build Coastguard Worker        dest.append(_positive_int(args_list[i]))
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker    return dest
32*387f9dfdSAndroid Build Coastguard Worker
33*387f9dfdSAndroid Build Coastguard Workerdef _positive_int(val):
34*387f9dfdSAndroid Build Coastguard Worker    try:
35*387f9dfdSAndroid Build Coastguard Worker        ival = int(val)
36*387f9dfdSAndroid Build Coastguard Worker    except ValueError:
37*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be an integer")
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker    if ival < 0:
40*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be positive")
41*387f9dfdSAndroid Build Coastguard Worker    return ival
42*387f9dfdSAndroid Build Coastguard Worker
43*387f9dfdSAndroid Build Coastguard Workerdef positive_nonzero_int(val):
44*387f9dfdSAndroid Build Coastguard Worker    ival = _positive_int(val)
45*387f9dfdSAndroid Build Coastguard Worker    if ival == 0:
46*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be nonzero")
47*387f9dfdSAndroid Build Coastguard Worker    return ival
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard Workerdef build_filter(filter_name, values):
50*387f9dfdSAndroid Build Coastguard Worker    filter_string = "((%s == %d)" % (filter_name, values[0])
51*387f9dfdSAndroid Build Coastguard Worker
52*387f9dfdSAndroid Build Coastguard Worker    for val in values[1:]:
53*387f9dfdSAndroid Build Coastguard Worker        filter_string += " || (%s == %d )" % (filter_name , val)
54*387f9dfdSAndroid Build Coastguard Worker
55*387f9dfdSAndroid Build Coastguard Worker    filter_string += ")"
56*387f9dfdSAndroid Build Coastguard Worker
57*387f9dfdSAndroid Build Coastguard Worker    return filter_string
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Workerdef stack_id_err(stack_id):
60*387f9dfdSAndroid Build Coastguard Worker    # -EFAULT in get_stackid normally means the stack-trace is not available,
61*387f9dfdSAndroid Build Coastguard Worker    # Such as getting kernel stack trace in userspace code
62*387f9dfdSAndroid Build Coastguard Worker    return (stack_id < 0) and (stack_id != -errno.EFAULT)
63*387f9dfdSAndroid Build Coastguard Worker
64*387f9dfdSAndroid Build Coastguard Worker# arguments
65*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
66*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime             # trace off-CPU + waker stack time until Ctrl-C
67*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime 5           # trace for 5 seconds only
68*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -f 5        # 5 seconds, and output in folded format
69*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -m 1000     # trace only events that last more than 1000 usec
70*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -M 9000     # trace only events that last less than 9000 usec
71*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -p 185      # only trace threads for PID 185
72*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -t 188      # only trace thread 188
73*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -u          # only trace user threads (no kernel)
74*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -k          # only trace kernel threads (no user)
75*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -U          # only show user space stacks (no kernel)
76*387f9dfdSAndroid Build Coastguard Worker    ./offwaketime -K          # only show kernel space stacks (no user)
77*387f9dfdSAndroid Build Coastguard Worker"""
78*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
79*387f9dfdSAndroid Build Coastguard Worker    description="Summarize blocked time by kernel stack trace + waker stack",
80*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
81*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
82*387f9dfdSAndroid Build Coastguard Workerthread_group = parser.add_mutually_exclusive_group()
83*387f9dfdSAndroid Build Coastguard Worker# Note: this script provides --pid and --tid flags but their arguments are
84*387f9dfdSAndroid Build Coastguard Worker# referred to internally using kernel nomenclature: TGID and PID.
85*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-p", "--pid", metavar="PIDS", dest="tgid",
86*387f9dfdSAndroid Build Coastguard Worker     type=positive_int,
87*387f9dfdSAndroid Build Coastguard Worker     help="trace these PIDS only. Can be a comma separated list of PIDS.")
88*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-t", "--tid", metavar="TIDS", dest="pid",
89*387f9dfdSAndroid Build Coastguard Worker    type=positive_int,
90*387f9dfdSAndroid Build Coastguard Worker    help="trace these TIDS only. Can be a comma separated list of TIDS.")
91*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-u", "--user-threads-only", action="store_true",
92*387f9dfdSAndroid Build Coastguard Worker    help="user threads only (no kernel threads)")
93*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-k", "--kernel-threads-only", action="store_true",
94*387f9dfdSAndroid Build Coastguard Worker    help="kernel threads only (no user threads)")
95*387f9dfdSAndroid Build Coastguard Workerstack_group = parser.add_mutually_exclusive_group()
96*387f9dfdSAndroid Build Coastguard Workerstack_group.add_argument("-U", "--user-stacks-only", action="store_true",
97*387f9dfdSAndroid Build Coastguard Worker    help="show stacks from user space only (no kernel space stacks)")
98*387f9dfdSAndroid Build Coastguard Workerstack_group.add_argument("-K", "--kernel-stacks-only", action="store_true",
99*387f9dfdSAndroid Build Coastguard Worker    help="show stacks from kernel space only (no user space stacks)")
100*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--delimited", action="store_true",
101*387f9dfdSAndroid Build Coastguard Worker    help="insert delimiter between kernel/user stacks")
102*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-f", "--folded", action="store_true",
103*387f9dfdSAndroid Build Coastguard Worker    help="output folded format")
104*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--stack-storage-size", default=16384,
105*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
106*387f9dfdSAndroid Build Coastguard Worker    help="the number of unique stack traces that can be stored and "
107*387f9dfdSAndroid Build Coastguard Worker         "displayed (default 16384)")
108*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("duration", nargs="?", default=99999999,
109*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
110*387f9dfdSAndroid Build Coastguard Worker    help="duration of trace, in seconds")
111*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-m", "--min-block-time", default=1,
112*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
113*387f9dfdSAndroid Build Coastguard Worker    help="the amount of time in microseconds over which we " +
114*387f9dfdSAndroid Build Coastguard Worker         "store traces (default 1)")
115*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-M", "--max-block-time", default=(1 << 64) - 1,
116*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
117*387f9dfdSAndroid Build Coastguard Worker    help="the amount of time in microseconds under which we " +
118*387f9dfdSAndroid Build Coastguard Worker         "store traces (default U64_MAX)")
119*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--state", type=_positive_int,
120*387f9dfdSAndroid Build Coastguard Worker    help="filter on this thread state bitmask (eg, 2 == TASK_UNINTERRUPTIBLE" +
121*387f9dfdSAndroid Build Coastguard Worker         ") see include/linux/sched.h")
122*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
123*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
124*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
125*387f9dfdSAndroid Build Coastguard Workerfolded = args.folded
126*387f9dfdSAndroid Build Coastguard Workerduration = int(args.duration)
127*387f9dfdSAndroid Build Coastguard Worker
128*387f9dfdSAndroid Build Coastguard Worker# signal handler
129*387f9dfdSAndroid Build Coastguard Workerdef signal_ignore(signal, frame):
130*387f9dfdSAndroid Build Coastguard Worker    print()
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Worker# define BPF program
133*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
134*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
135*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Worker#define MINBLOCK_US    MINBLOCK_US_VALUEULL
138*387f9dfdSAndroid Build Coastguard Worker#define MAXBLOCK_US    MAXBLOCK_US_VALUEULL
139*387f9dfdSAndroid Build Coastguard Worker
140*387f9dfdSAndroid Build Coastguard Workerstruct key_t {
141*387f9dfdSAndroid Build Coastguard Worker    char waker[TASK_COMM_LEN];
142*387f9dfdSAndroid Build Coastguard Worker    char target[TASK_COMM_LEN];
143*387f9dfdSAndroid Build Coastguard Worker    s64 w_k_stack_id;
144*387f9dfdSAndroid Build Coastguard Worker    s64 w_u_stack_id;
145*387f9dfdSAndroid Build Coastguard Worker    s64 t_k_stack_id;
146*387f9dfdSAndroid Build Coastguard Worker    s64 t_u_stack_id;
147*387f9dfdSAndroid Build Coastguard Worker    u64 t_pid;
148*387f9dfdSAndroid Build Coastguard Worker    u64 t_tgid;
149*387f9dfdSAndroid Build Coastguard Worker    u32 w_pid;
150*387f9dfdSAndroid Build Coastguard Worker    u32 w_tgid;
151*387f9dfdSAndroid Build Coastguard Worker};
152*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(counts, struct key_t);
153*387f9dfdSAndroid Build Coastguard Worker
154*387f9dfdSAndroid Build Coastguard Worker// Key of this hash is PID of waiting Process,
155*387f9dfdSAndroid Build Coastguard Worker// value is timestamp when it went into waiting
156*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, u32);
157*387f9dfdSAndroid Build Coastguard Worker
158*387f9dfdSAndroid Build Coastguard Workerstruct wokeby_t {
159*387f9dfdSAndroid Build Coastguard Worker    char name[TASK_COMM_LEN];
160*387f9dfdSAndroid Build Coastguard Worker    int k_stack_id;
161*387f9dfdSAndroid Build Coastguard Worker    int u_stack_id;
162*387f9dfdSAndroid Build Coastguard Worker    int w_pid;
163*387f9dfdSAndroid Build Coastguard Worker    int w_tgid;
164*387f9dfdSAndroid Build Coastguard Worker};
165*387f9dfdSAndroid Build Coastguard Worker// Key of the hash is PID of the Process to be waken, value is information
166*387f9dfdSAndroid Build Coastguard Worker// of the Process who wakes it
167*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(wokeby, u32, struct wokeby_t);
168*387f9dfdSAndroid Build Coastguard Worker
169*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, STACK_STORAGE_SIZE);
170*387f9dfdSAndroid Build Coastguard Worker
171*387f9dfdSAndroid Build Coastguard Workerint waker(struct pt_regs *ctx, struct task_struct *p) {
172*387f9dfdSAndroid Build Coastguard Worker    // PID and TGID of the target Process to be waken
173*387f9dfdSAndroid Build Coastguard Worker    u32 pid = p->pid;
174*387f9dfdSAndroid Build Coastguard Worker    u32 tgid = p->tgid;
175*387f9dfdSAndroid Build Coastguard Worker
176*387f9dfdSAndroid Build Coastguard Worker    if (!((THREAD_FILTER) && (STATE_FILTER))) {
177*387f9dfdSAndroid Build Coastguard Worker        return 0;
178*387f9dfdSAndroid Build Coastguard Worker    }
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker    // Construct information about current (the waker) Process
181*387f9dfdSAndroid Build Coastguard Worker    struct wokeby_t woke = {};
182*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&woke.name, sizeof(woke.name));
183*387f9dfdSAndroid Build Coastguard Worker    woke.k_stack_id = KERNEL_STACK_GET;
184*387f9dfdSAndroid Build Coastguard Worker    woke.u_stack_id = USER_STACK_GET;
185*387f9dfdSAndroid Build Coastguard Worker    woke.w_pid = bpf_get_current_pid_tgid();
186*387f9dfdSAndroid Build Coastguard Worker    woke.w_tgid = bpf_get_current_pid_tgid() >> 32;
187*387f9dfdSAndroid Build Coastguard Worker
188*387f9dfdSAndroid Build Coastguard Worker    wokeby.update(&pid, &woke);
189*387f9dfdSAndroid Build Coastguard Worker    return 0;
190*387f9dfdSAndroid Build Coastguard Worker}
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Workerint oncpu(struct pt_regs *ctx, struct task_struct *p) {
193*387f9dfdSAndroid Build Coastguard Worker    // PID and TGID of the previous Process (Process going into waiting)
194*387f9dfdSAndroid Build Coastguard Worker    u32 pid = p->pid;
195*387f9dfdSAndroid Build Coastguard Worker    u32 tgid = p->tgid;
196*387f9dfdSAndroid Build Coastguard Worker    u64 *tsp;
197*387f9dfdSAndroid Build Coastguard Worker    u64 ts = bpf_ktime_get_ns();
198*387f9dfdSAndroid Build Coastguard Worker
199*387f9dfdSAndroid Build Coastguard Worker    // Record timestamp for the previous Process (Process going into waiting)
200*387f9dfdSAndroid Build Coastguard Worker    if ((THREAD_FILTER) && (STATE_FILTER)) {
201*387f9dfdSAndroid Build Coastguard Worker        start.update(&pid, &ts);
202*387f9dfdSAndroid Build Coastguard Worker    }
203*387f9dfdSAndroid Build Coastguard Worker
204*387f9dfdSAndroid Build Coastguard Worker    // Calculate current Process's wait time by finding the timestamp of when
205*387f9dfdSAndroid Build Coastguard Worker    // it went into waiting.
206*387f9dfdSAndroid Build Coastguard Worker    // pid and tgid are now the PID and TGID of the current (waking) Process.
207*387f9dfdSAndroid Build Coastguard Worker    pid = bpf_get_current_pid_tgid();
208*387f9dfdSAndroid Build Coastguard Worker    tgid = bpf_get_current_pid_tgid() >> 32;
209*387f9dfdSAndroid Build Coastguard Worker    tsp = start.lookup(&pid);
210*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0) {
211*387f9dfdSAndroid Build Coastguard Worker        // Missed or filtered when the Process went into waiting
212*387f9dfdSAndroid Build Coastguard Worker        return 0;
213*387f9dfdSAndroid Build Coastguard Worker    }
214*387f9dfdSAndroid Build Coastguard Worker    u64 delta = ts - *tsp;
215*387f9dfdSAndroid Build Coastguard Worker    start.delete(&pid);
216*387f9dfdSAndroid Build Coastguard Worker    delta = delta / 1000;
217*387f9dfdSAndroid Build Coastguard Worker    if ((delta < MINBLOCK_US) || (delta > MAXBLOCK_US)) {
218*387f9dfdSAndroid Build Coastguard Worker        return 0;
219*387f9dfdSAndroid Build Coastguard Worker    }
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Worker    // create map key
222*387f9dfdSAndroid Build Coastguard Worker    struct key_t key = {};
223*387f9dfdSAndroid Build Coastguard Worker    struct wokeby_t *woke;
224*387f9dfdSAndroid Build Coastguard Worker
225*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&key.target, sizeof(key.target));
226*387f9dfdSAndroid Build Coastguard Worker    key.t_pid = pid;
227*387f9dfdSAndroid Build Coastguard Worker    key.t_tgid = tgid;
228*387f9dfdSAndroid Build Coastguard Worker    key.t_k_stack_id = KERNEL_STACK_GET;
229*387f9dfdSAndroid Build Coastguard Worker    key.t_u_stack_id = USER_STACK_GET;
230*387f9dfdSAndroid Build Coastguard Worker
231*387f9dfdSAndroid Build Coastguard Worker    woke = wokeby.lookup(&pid);
232*387f9dfdSAndroid Build Coastguard Worker    if (woke) {
233*387f9dfdSAndroid Build Coastguard Worker        key.w_k_stack_id = woke->k_stack_id;
234*387f9dfdSAndroid Build Coastguard Worker        key.w_u_stack_id = woke->u_stack_id;
235*387f9dfdSAndroid Build Coastguard Worker        key.w_pid = woke->w_pid;
236*387f9dfdSAndroid Build Coastguard Worker        key.w_tgid = woke->w_tgid;
237*387f9dfdSAndroid Build Coastguard Worker        __builtin_memcpy(&key.waker, woke->name, TASK_COMM_LEN);
238*387f9dfdSAndroid Build Coastguard Worker        wokeby.delete(&pid);
239*387f9dfdSAndroid Build Coastguard Worker    }
240*387f9dfdSAndroid Build Coastguard Worker
241*387f9dfdSAndroid Build Coastguard Worker    counts.increment(key, delta);
242*387f9dfdSAndroid Build Coastguard Worker    return 0;
243*387f9dfdSAndroid Build Coastguard Worker}
244*387f9dfdSAndroid Build Coastguard Worker"""
245*387f9dfdSAndroid Build Coastguard Worker
246*387f9dfdSAndroid Build Coastguard Worker# set thread filter
247*387f9dfdSAndroid Build Coastguard Workerif args.tgid is not None:
248*387f9dfdSAndroid Build Coastguard Worker    thread_filter = build_filter("tgid", args.tgid)
249*387f9dfdSAndroid Build Coastguard Workerelif args.pid is not None:
250*387f9dfdSAndroid Build Coastguard Worker    thread_filter = build_filter("pid", args.pid)
251*387f9dfdSAndroid Build Coastguard Workerelif args.user_threads_only:
252*387f9dfdSAndroid Build Coastguard Worker    thread_filter = '!(p->flags & PF_KTHREAD)'
253*387f9dfdSAndroid Build Coastguard Workerelif args.kernel_threads_only:
254*387f9dfdSAndroid Build Coastguard Worker    thread_filter = 'p->flags & PF_KTHREAD'
255*387f9dfdSAndroid Build Coastguard Workerelse:
256*387f9dfdSAndroid Build Coastguard Worker    thread_filter = '1'
257*387f9dfdSAndroid Build Coastguard Workerif args.state == 0:
258*387f9dfdSAndroid Build Coastguard Worker    state_filter = 'p->STATE_FIELD == 0'
259*387f9dfdSAndroid Build Coastguard Workerelif args.state:
260*387f9dfdSAndroid Build Coastguard Worker    # these states are sometimes bitmask checked
261*387f9dfdSAndroid Build Coastguard Worker    state_filter = 'p->STATE_FIELD & %d' % args.state
262*387f9dfdSAndroid Build Coastguard Workerelse:
263*387f9dfdSAndroid Build Coastguard Worker    state_filter = '1'
264*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('THREAD_FILTER', thread_filter)
265*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('STATE_FILTER', state_filter)
266*387f9dfdSAndroid Build Coastguard Workerif BPF.kernel_struct_has_field(b'task_struct', b'__state') == 1:
267*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('STATE_FIELD', '__state')
268*387f9dfdSAndroid Build Coastguard Workerelse:
269*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('STATE_FIELD', 'state')
270*387f9dfdSAndroid Build Coastguard Worker
271*387f9dfdSAndroid Build Coastguard Worker# set stack storage size
272*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('STACK_STORAGE_SIZE', str(args.stack_storage_size))
273*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('MINBLOCK_US_VALUE', str(args.min_block_time))
274*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('MAXBLOCK_US_VALUE', str(args.max_block_time))
275*387f9dfdSAndroid Build Coastguard Worker
276*387f9dfdSAndroid Build Coastguard Worker# handle stack args
277*387f9dfdSAndroid Build Coastguard Workerkernel_stack_get = "stack_traces.get_stackid(ctx, 0)"
278*387f9dfdSAndroid Build Coastguard Workeruser_stack_get = "stack_traces.get_stackid(ctx, BPF_F_USER_STACK)"
279*387f9dfdSAndroid Build Coastguard Workerstack_context = ""
280*387f9dfdSAndroid Build Coastguard Workerif args.user_stacks_only:
281*387f9dfdSAndroid Build Coastguard Worker    stack_context = "user"
282*387f9dfdSAndroid Build Coastguard Worker    kernel_stack_get = "-1"
283*387f9dfdSAndroid Build Coastguard Workerelif args.kernel_stacks_only:
284*387f9dfdSAndroid Build Coastguard Worker    stack_context = "kernel"
285*387f9dfdSAndroid Build Coastguard Worker    user_stack_get = "-1"
286*387f9dfdSAndroid Build Coastguard Workerelse:
287*387f9dfdSAndroid Build Coastguard Worker    stack_context = "user + kernel"
288*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('USER_STACK_GET', user_stack_get)
289*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('KERNEL_STACK_GET', kernel_stack_get)
290*387f9dfdSAndroid Build Coastguard Workerif args.ebpf:
291*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
292*387f9dfdSAndroid Build Coastguard Worker    exit()
293*387f9dfdSAndroid Build Coastguard Worker
294*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
295*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
296*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event_re="^finish_task_switch$|^finish_task_switch\.isra\.\d$",
297*387f9dfdSAndroid Build Coastguard Worker                fn_name="oncpu")
298*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="try_to_wake_up", fn_name="waker")
299*387f9dfdSAndroid Build Coastguard Workermatched = b.num_open_kprobes()
300*387f9dfdSAndroid Build Coastguard Workerif matched == 0:
301*387f9dfdSAndroid Build Coastguard Worker    print("0 functions traced. Exiting.")
302*387f9dfdSAndroid Build Coastguard Worker    exit()
303*387f9dfdSAndroid Build Coastguard Worker
304*387f9dfdSAndroid Build Coastguard Worker# header
305*387f9dfdSAndroid Build Coastguard Workerif not folded:
306*387f9dfdSAndroid Build Coastguard Worker    print("Tracing blocked time (us) by %s off-CPU and waker stack" %
307*387f9dfdSAndroid Build Coastguard Worker        stack_context, end="")
308*387f9dfdSAndroid Build Coastguard Worker    if duration < 99999999:
309*387f9dfdSAndroid Build Coastguard Worker        print(" for %d secs." % duration)
310*387f9dfdSAndroid Build Coastguard Worker    else:
311*387f9dfdSAndroid Build Coastguard Worker        print("... Hit Ctrl-C to end.")
312*387f9dfdSAndroid Build Coastguard Worker
313*387f9dfdSAndroid Build Coastguard Workertry:
314*387f9dfdSAndroid Build Coastguard Worker    sleep(duration)
315*387f9dfdSAndroid Build Coastguard Workerexcept KeyboardInterrupt:
316*387f9dfdSAndroid Build Coastguard Worker    # as cleanup can take many seconds, trap Ctrl-C:
317*387f9dfdSAndroid Build Coastguard Worker    # print a newline for folded output on Ctrl-C
318*387f9dfdSAndroid Build Coastguard Worker    signal.signal(signal.SIGINT, signal_ignore)
319*387f9dfdSAndroid Build Coastguard Worker
320*387f9dfdSAndroid Build Coastguard Worker
321*387f9dfdSAndroid Build Coastguard Workerif not folded:
322*387f9dfdSAndroid Build Coastguard Worker    print()
323*387f9dfdSAndroid Build Coastguard Worker
324*387f9dfdSAndroid Build Coastguard Workermissing_stacks = 0
325*387f9dfdSAndroid Build Coastguard Workerhas_enomem = False
326*387f9dfdSAndroid Build Coastguard Workercounts = b.get_table("counts")
327*387f9dfdSAndroid Build Coastguard Workerstack_traces = b.get_table("stack_traces")
328*387f9dfdSAndroid Build Coastguard Workerneed_delimiter = args.delimited and not (args.kernel_stacks_only or
329*387f9dfdSAndroid Build Coastguard Worker                                         args.user_stacks_only)
330*387f9dfdSAndroid Build Coastguard Workerfor k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
331*387f9dfdSAndroid Build Coastguard Worker    # handle get_stackid errors
332*387f9dfdSAndroid Build Coastguard Worker    if not args.user_stacks_only:
333*387f9dfdSAndroid Build Coastguard Worker        missing_stacks += int(stack_id_err(k.w_k_stack_id))
334*387f9dfdSAndroid Build Coastguard Worker        missing_stacks += int(stack_id_err(k.t_k_stack_id))
335*387f9dfdSAndroid Build Coastguard Worker        has_enomem = has_enomem or (k.w_k_stack_id == -errno.ENOMEM) or \
336*387f9dfdSAndroid Build Coastguard Worker                     (k.t_k_stack_id == -errno.ENOMEM)
337*387f9dfdSAndroid Build Coastguard Worker    if not args.kernel_stacks_only:
338*387f9dfdSAndroid Build Coastguard Worker        missing_stacks += int(stack_id_err(k.w_u_stack_id))
339*387f9dfdSAndroid Build Coastguard Worker        missing_stacks += int(stack_id_err(k.t_u_stack_id))
340*387f9dfdSAndroid Build Coastguard Worker        has_enomem = has_enomem or (k.w_u_stack_id == -errno.ENOMEM) or \
341*387f9dfdSAndroid Build Coastguard Worker                     (k.t_u_stack_id == -errno.ENOMEM)
342*387f9dfdSAndroid Build Coastguard Worker
343*387f9dfdSAndroid Build Coastguard Worker    waker_user_stack = [] if k.w_u_stack_id < 1 else \
344*387f9dfdSAndroid Build Coastguard Worker        reversed(list(stack_traces.walk(k.w_u_stack_id))[1:])
345*387f9dfdSAndroid Build Coastguard Worker    waker_kernel_stack = [] if k.w_k_stack_id < 1 else \
346*387f9dfdSAndroid Build Coastguard Worker        reversed(list(stack_traces.walk(k.w_k_stack_id))[1:])
347*387f9dfdSAndroid Build Coastguard Worker    target_user_stack = [] if k.t_u_stack_id < 1 else \
348*387f9dfdSAndroid Build Coastguard Worker        stack_traces.walk(k.t_u_stack_id)
349*387f9dfdSAndroid Build Coastguard Worker    target_kernel_stack = [] if k.t_k_stack_id < 1 else \
350*387f9dfdSAndroid Build Coastguard Worker        stack_traces.walk(k.t_k_stack_id)
351*387f9dfdSAndroid Build Coastguard Worker
352*387f9dfdSAndroid Build Coastguard Worker    if folded:
353*387f9dfdSAndroid Build Coastguard Worker        # print folded stack output
354*387f9dfdSAndroid Build Coastguard Worker        line = [k.target.decode('utf-8', 'replace')]
355*387f9dfdSAndroid Build Coastguard Worker        if not args.kernel_stacks_only:
356*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.t_u_stack_id):
357*387f9dfdSAndroid Build Coastguard Worker                line.append("[Missed User Stack] %d" % k.t_u_stack_id)
358*387f9dfdSAndroid Build Coastguard Worker            else:
359*387f9dfdSAndroid Build Coastguard Worker                line.extend([b.sym(addr, k.t_tgid).decode('utf-8', 'replace')
360*387f9dfdSAndroid Build Coastguard Worker                    for addr in reversed(list(target_user_stack)[1:])])
361*387f9dfdSAndroid Build Coastguard Worker        if not args.user_stacks_only:
362*387f9dfdSAndroid Build Coastguard Worker            line.extend(["-"] if (need_delimiter and k.t_k_stack_id > 0 and k.t_u_stack_id > 0) else [])
363*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.t_k_stack_id):
364*387f9dfdSAndroid Build Coastguard Worker                line.append("[Missed Kernel Stack]")
365*387f9dfdSAndroid Build Coastguard Worker            else:
366*387f9dfdSAndroid Build Coastguard Worker                line.extend([b.ksym(addr).decode('utf-8', 'replace')
367*387f9dfdSAndroid Build Coastguard Worker                    for addr in reversed(list(target_kernel_stack)[1:])])
368*387f9dfdSAndroid Build Coastguard Worker        line.append("--")
369*387f9dfdSAndroid Build Coastguard Worker        if not args.user_stacks_only:
370*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.w_k_stack_id):
371*387f9dfdSAndroid Build Coastguard Worker                line.append("[Missed Kernel Stack]")
372*387f9dfdSAndroid Build Coastguard Worker            else:
373*387f9dfdSAndroid Build Coastguard Worker                line.extend([b.ksym(addr).decode('utf-8', 'replace')
374*387f9dfdSAndroid Build Coastguard Worker                    for addr in reversed(list(waker_kernel_stack))])
375*387f9dfdSAndroid Build Coastguard Worker        if not args.kernel_stacks_only:
376*387f9dfdSAndroid Build Coastguard Worker            line.extend(["-"] if (need_delimiter and k.w_u_stack_id > 0 and k.w_k_stack_id > 0) else [])
377*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.w_u_stack_id):
378*387f9dfdSAndroid Build Coastguard Worker                line.append("[Missed User Stack]")
379*387f9dfdSAndroid Build Coastguard Worker            else:
380*387f9dfdSAndroid Build Coastguard Worker                line.extend([b.sym(addr, k.w_tgid).decode('utf-8', 'replace')
381*387f9dfdSAndroid Build Coastguard Worker                    for addr in reversed(list(waker_user_stack))])
382*387f9dfdSAndroid Build Coastguard Worker        line.append(k.waker.decode('utf-8', 'replace'))
383*387f9dfdSAndroid Build Coastguard Worker        print("%s %d" % (";".join(line), v.value))
384*387f9dfdSAndroid Build Coastguard Worker    else:
385*387f9dfdSAndroid Build Coastguard Worker        # print wakeup name then stack in reverse order
386*387f9dfdSAndroid Build Coastguard Worker        print("    %-16s %s %s" % ("waker:", k.waker.decode('utf-8', 'replace'), k.w_pid))
387*387f9dfdSAndroid Build Coastguard Worker        if not args.kernel_stacks_only:
388*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.w_u_stack_id):
389*387f9dfdSAndroid Build Coastguard Worker                print("    [Missed User Stack] %d" % k.w_u_stack_id)
390*387f9dfdSAndroid Build Coastguard Worker            else:
391*387f9dfdSAndroid Build Coastguard Worker                for addr in waker_user_stack:
392*387f9dfdSAndroid Build Coastguard Worker                    print("    %s" % b.sym(addr, k.w_tgid).decode('utf-8', 'replace'))
393*387f9dfdSAndroid Build Coastguard Worker        if not args.user_stacks_only:
394*387f9dfdSAndroid Build Coastguard Worker            if need_delimiter and k.w_u_stack_id > 0 and k.w_k_stack_id > 0:
395*387f9dfdSAndroid Build Coastguard Worker                print("    -")
396*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.w_k_stack_id):
397*387f9dfdSAndroid Build Coastguard Worker                print("    [Missed Kernel Stack]")
398*387f9dfdSAndroid Build Coastguard Worker            else:
399*387f9dfdSAndroid Build Coastguard Worker                for addr in waker_kernel_stack:
400*387f9dfdSAndroid Build Coastguard Worker                    print("    %s" % b.ksym(addr).decode('utf-8', 'replace'))
401*387f9dfdSAndroid Build Coastguard Worker
402*387f9dfdSAndroid Build Coastguard Worker        # print waker/wakee delimiter
403*387f9dfdSAndroid Build Coastguard Worker        print("    %-16s %s" % ("--", "--"))
404*387f9dfdSAndroid Build Coastguard Worker
405*387f9dfdSAndroid Build Coastguard Worker        if not args.user_stacks_only:
406*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.t_k_stack_id):
407*387f9dfdSAndroid Build Coastguard Worker                print("    [Missed Kernel Stack]")
408*387f9dfdSAndroid Build Coastguard Worker            else:
409*387f9dfdSAndroid Build Coastguard Worker                for addr in target_kernel_stack:
410*387f9dfdSAndroid Build Coastguard Worker                    print("    %s" % b.ksym(addr).decode('utf-8', 'replace'))
411*387f9dfdSAndroid Build Coastguard Worker        if not args.kernel_stacks_only:
412*387f9dfdSAndroid Build Coastguard Worker            if need_delimiter and k.t_u_stack_id > 0 and k.t_k_stack_id > 0:
413*387f9dfdSAndroid Build Coastguard Worker                print("    -")
414*387f9dfdSAndroid Build Coastguard Worker            if stack_id_err(k.t_u_stack_id):
415*387f9dfdSAndroid Build Coastguard Worker                print("    [Missed User Stack]")
416*387f9dfdSAndroid Build Coastguard Worker            else:
417*387f9dfdSAndroid Build Coastguard Worker                for addr in target_user_stack:
418*387f9dfdSAndroid Build Coastguard Worker                    print("    %s" % b.sym(addr, k.t_tgid).decode('utf-8', 'replace'))
419*387f9dfdSAndroid Build Coastguard Worker        print("    %-16s %s %s" % ("target:", k.target.decode('utf-8', 'replace'), k.t_pid))
420*387f9dfdSAndroid Build Coastguard Worker        print("        %d\n" % v.value)
421*387f9dfdSAndroid Build Coastguard Worker
422*387f9dfdSAndroid Build Coastguard Workerif missing_stacks > 0:
423*387f9dfdSAndroid Build Coastguard Worker    enomem_str = " Consider increasing --stack-storage-size."
424*387f9dfdSAndroid Build Coastguard Worker    print("WARNING: %d stack traces lost and could not be displayed.%s" %
425*387f9dfdSAndroid Build Coastguard Worker        (missing_stacks, (enomem_str if has_enomem else "")),
426*387f9dfdSAndroid Build Coastguard Worker        file=stderr)
427