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