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