1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# profile Profile CPU usage by sampling stack traces at a timed interval. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, BPF, perf_events. Embedded C. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# This is an efficient profiler, as stack traces are frequency counted in 8*387f9dfdSAndroid Build Coastguard Worker# kernel context, rather than passing every stack to user space for frequency 9*387f9dfdSAndroid Build Coastguard Worker# counting there. Only the unique stacks and counts are passed to user space 10*387f9dfdSAndroid Build Coastguard Worker# at the end of the profile, greatly reducing the kernel<->user transfer. 11*387f9dfdSAndroid Build Coastguard Worker# 12*387f9dfdSAndroid Build Coastguard Worker# By default CPU idle stacks are excluded by simply excluding PID 0. 13*387f9dfdSAndroid Build Coastguard Worker# 14*387f9dfdSAndroid Build Coastguard Worker# REQUIRES: Linux 4.9+ (BPF_PROG_TYPE_PERF_EVENT support). Under tools/old is 15*387f9dfdSAndroid Build Coastguard Worker# a version of this tool that may work on Linux 4.6 - 4.8. 16*387f9dfdSAndroid Build Coastguard Worker# 17*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 18*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 19*387f9dfdSAndroid Build Coastguard Worker# 20*387f9dfdSAndroid Build Coastguard Worker# THANKS: Alexei Starovoitov, who added proper BPF profiling support to Linux; 21*387f9dfdSAndroid Build Coastguard Worker# Sasha Goldshtein, Andrew Birchall, and Evgeny Vereshchagin, who wrote much 22*387f9dfdSAndroid Build Coastguard Worker# of the code here, borrowed from tracepoint.py and offcputime.py; and 23*387f9dfdSAndroid Build Coastguard Worker# Teng Qin, who added perf support in bcc. 24*387f9dfdSAndroid Build Coastguard Worker# 25*387f9dfdSAndroid Build Coastguard Worker# 15-Jul-2016 Brendan Gregg Created this. 26*387f9dfdSAndroid Build Coastguard Worker# 20-Oct-2016 " " Switched to use the new 4.9 support. 27*387f9dfdSAndroid Build Coastguard Worker# 26-Jan-2019 " " Changed to exclude CPU idle by default. 28*387f9dfdSAndroid Build Coastguard Worker# 11-Apr-2023 Rocky Xing Added option to increase hash storage size. 29*387f9dfdSAndroid Build Coastguard Worker 30*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 31*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, PerfType, PerfSWConfig 32*387f9dfdSAndroid Build Coastguard Workerfrom bcc.containers import filter_by_containers 33*387f9dfdSAndroid Build Coastguard Workerfrom sys import stderr 34*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep 35*387f9dfdSAndroid Build Coastguard Workerimport argparse 36*387f9dfdSAndroid Build Coastguard Workerimport signal 37*387f9dfdSAndroid Build Coastguard Workerimport os 38*387f9dfdSAndroid Build Coastguard Workerimport errno 39*387f9dfdSAndroid Build Coastguard Worker 40*387f9dfdSAndroid Build Coastguard Worker# 41*387f9dfdSAndroid Build Coastguard Worker# Process Arguments 42*387f9dfdSAndroid Build Coastguard Worker# 43*387f9dfdSAndroid Build Coastguard Worker 44*387f9dfdSAndroid Build Coastguard Worker# arg validation 45*387f9dfdSAndroid Build Coastguard Workerdef positive_int(val): 46*387f9dfdSAndroid Build Coastguard Worker try: 47*387f9dfdSAndroid Build Coastguard Worker ival = int(val) 48*387f9dfdSAndroid Build Coastguard Worker except ValueError: 49*387f9dfdSAndroid Build Coastguard Worker raise argparse.ArgumentTypeError("must be an integer") 50*387f9dfdSAndroid Build Coastguard Worker 51*387f9dfdSAndroid Build Coastguard Worker if ival < 0: 52*387f9dfdSAndroid Build Coastguard Worker raise argparse.ArgumentTypeError("must be positive") 53*387f9dfdSAndroid Build Coastguard Worker return ival 54*387f9dfdSAndroid Build Coastguard Worker 55*387f9dfdSAndroid Build Coastguard Workerdef positive_int_list(val): 56*387f9dfdSAndroid Build Coastguard Worker vlist = val.split(",") 57*387f9dfdSAndroid Build Coastguard Worker if len(vlist) <= 0: 58*387f9dfdSAndroid Build Coastguard Worker raise argparse.ArgumentTypeError("must be an integer list") 59*387f9dfdSAndroid Build Coastguard Worker 60*387f9dfdSAndroid Build Coastguard Worker return [positive_int(v) for v in vlist] 61*387f9dfdSAndroid Build Coastguard Worker 62*387f9dfdSAndroid Build Coastguard Workerdef positive_nonzero_int(val): 63*387f9dfdSAndroid Build Coastguard Worker ival = positive_int(val) 64*387f9dfdSAndroid Build Coastguard Worker if ival == 0: 65*387f9dfdSAndroid Build Coastguard Worker raise argparse.ArgumentTypeError("must be nonzero") 66*387f9dfdSAndroid Build Coastguard Worker return ival 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Workerdef stack_id_err(stack_id): 69*387f9dfdSAndroid Build Coastguard Worker # -EFAULT in get_stackid normally means the stack-trace is not available, 70*387f9dfdSAndroid Build Coastguard Worker # Such as getting kernel stack trace in userspace code 71*387f9dfdSAndroid Build Coastguard Worker return (stack_id < 0) and (stack_id != -errno.EFAULT) 72*387f9dfdSAndroid Build Coastguard Worker 73*387f9dfdSAndroid Build Coastguard Worker# arguments 74*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 75*387f9dfdSAndroid Build Coastguard Worker ./profile # profile stack traces at 49 Hertz until Ctrl-C 76*387f9dfdSAndroid Build Coastguard Worker ./profile -F 99 # profile stack traces at 99 Hertz 77*387f9dfdSAndroid Build Coastguard Worker ./profile -c 1000000 # profile stack traces every 1 in a million events 78*387f9dfdSAndroid Build Coastguard Worker ./profile 5 # profile at 49 Hertz for 5 seconds only 79*387f9dfdSAndroid Build Coastguard Worker ./profile -f 5 # output in folded format for flame graphs 80*387f9dfdSAndroid Build Coastguard Worker ./profile -p 185 # only profile process with PID 185 81*387f9dfdSAndroid Build Coastguard Worker ./profile -L 185 # only profile thread with TID 185 82*387f9dfdSAndroid Build Coastguard Worker ./profile -U # only show user space stacks (no kernel) 83*387f9dfdSAndroid Build Coastguard Worker ./profile -K # only show kernel space stacks (no user) 84*387f9dfdSAndroid Build Coastguard Worker ./profile --cgroupmap mappath # only trace cgroups in this BPF map 85*387f9dfdSAndroid Build Coastguard Worker ./profile --mntnsmap mappath # only trace mount namespaces in the map 86*387f9dfdSAndroid Build Coastguard Worker""" 87*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 88*387f9dfdSAndroid Build Coastguard Worker description="Profile CPU stack traces at a timed interval", 89*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 90*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 91*387f9dfdSAndroid Build Coastguard Workerthread_group = parser.add_mutually_exclusive_group() 92*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-p", "--pid", type=positive_int_list, 93*387f9dfdSAndroid Build Coastguard Worker help="profile process with one or more comma separated PIDs only") 94*387f9dfdSAndroid Build Coastguard Workerthread_group.add_argument("-L", "--tid", type=positive_int_list, 95*387f9dfdSAndroid Build Coastguard Worker help="profile thread with one or more comma separated TIDs only") 96*387f9dfdSAndroid Build Coastguard Worker# TODO: add options for user/kernel threads only 97*387f9dfdSAndroid Build Coastguard Workerstack_group = parser.add_mutually_exclusive_group() 98*387f9dfdSAndroid Build Coastguard Workerstack_group.add_argument("-U", "--user-stacks-only", action="store_true", 99*387f9dfdSAndroid Build Coastguard Worker help="show stacks from user space only (no kernel space stacks)") 100*387f9dfdSAndroid Build Coastguard Workerstack_group.add_argument("-K", "--kernel-stacks-only", action="store_true", 101*387f9dfdSAndroid Build Coastguard Worker help="show stacks from kernel space only (no user space stacks)") 102*387f9dfdSAndroid Build Coastguard Workersample_group = parser.add_mutually_exclusive_group() 103*387f9dfdSAndroid Build Coastguard Workersample_group.add_argument("-F", "--frequency", type=positive_int, 104*387f9dfdSAndroid Build Coastguard Worker help="sample frequency, Hertz") 105*387f9dfdSAndroid Build Coastguard Workersample_group.add_argument("-c", "--count", type=positive_int, 106*387f9dfdSAndroid Build Coastguard Worker help="sample period, number of events") 107*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--delimited", action="store_true", 108*387f9dfdSAndroid Build Coastguard Worker help="insert delimiter between kernel/user stacks") 109*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-a", "--annotations", action="store_true", 110*387f9dfdSAndroid Build Coastguard Worker help="add _[k] annotations to kernel frames") 111*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-I", "--include-idle", action="store_true", 112*387f9dfdSAndroid Build Coastguard Worker help="include CPU idle stacks") 113*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-f", "--folded", action="store_true", 114*387f9dfdSAndroid Build Coastguard Worker help="output folded format, one line per stack (for flame graphs)") 115*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--hash-storage-size", default=40960, 116*387f9dfdSAndroid Build Coastguard Worker type=positive_nonzero_int, 117*387f9dfdSAndroid Build Coastguard Worker help="the number of hash keys that can be stored and (default %(default)s)") 118*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--stack-storage-size", default=16384, 119*387f9dfdSAndroid Build Coastguard Worker type=positive_nonzero_int, 120*387f9dfdSAndroid Build Coastguard Worker help="the number of unique stack traces that can be stored and " 121*387f9dfdSAndroid Build Coastguard Worker "displayed (default %(default)s)") 122*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("duration", nargs="?", default=99999999, 123*387f9dfdSAndroid Build Coastguard Worker type=positive_nonzero_int, 124*387f9dfdSAndroid Build Coastguard Worker help="duration of trace, in seconds") 125*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-C", "--cpu", type=int, default=-1, 126*387f9dfdSAndroid Build Coastguard Worker help="cpu number to run profile on") 127*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 128*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 129*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--cgroupmap", 130*387f9dfdSAndroid Build Coastguard Worker help="trace cgroups in this BPF map only") 131*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--mntnsmap", 132*387f9dfdSAndroid Build Coastguard Worker help="trace mount namespaces in this BPF map only") 133*387f9dfdSAndroid Build Coastguard Worker 134*387f9dfdSAndroid Build Coastguard Worker# option logic 135*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 136*387f9dfdSAndroid Build Coastguard Workerduration = int(args.duration) 137*387f9dfdSAndroid Build Coastguard Workerdebug = 0 138*387f9dfdSAndroid Build Coastguard Workerneed_delimiter = args.delimited and not (args.kernel_stacks_only or 139*387f9dfdSAndroid Build Coastguard Worker args.user_stacks_only) 140*387f9dfdSAndroid Build Coastguard Worker# TODO: add stack depth, and interval 141*387f9dfdSAndroid Build Coastguard Worker 142*387f9dfdSAndroid Build Coastguard Worker# 143*387f9dfdSAndroid Build Coastguard Worker# Setup BPF 144*387f9dfdSAndroid Build Coastguard Worker# 145*387f9dfdSAndroid Build Coastguard Worker 146*387f9dfdSAndroid Build Coastguard Worker# define BPF program 147*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 148*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 149*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/bpf_perf_event.h> 150*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 151*387f9dfdSAndroid Build Coastguard Worker 152*387f9dfdSAndroid Build Coastguard Workerstruct key_t { 153*387f9dfdSAndroid Build Coastguard Worker u32 pid; 154*387f9dfdSAndroid Build Coastguard Worker u64 kernel_ip; 155*387f9dfdSAndroid Build Coastguard Worker int user_stack_id; 156*387f9dfdSAndroid Build Coastguard Worker int kernel_stack_id; 157*387f9dfdSAndroid Build Coastguard Worker char name[TASK_COMM_LEN]; 158*387f9dfdSAndroid Build Coastguard Worker}; 159*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(counts, struct key_t, u64, HASH_STORAGE_SIZE); 160*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, STACK_STORAGE_SIZE); 161*387f9dfdSAndroid Build Coastguard Worker 162*387f9dfdSAndroid Build Coastguard Worker// This code gets a bit complex. Probably not suitable for casual hacking. 163*387f9dfdSAndroid Build Coastguard Worker 164*387f9dfdSAndroid Build Coastguard Workerint do_perf_event(struct bpf_perf_event_data *ctx) { 165*387f9dfdSAndroid Build Coastguard Worker u32 tgid = 0; 166*387f9dfdSAndroid Build Coastguard Worker u32 pid = 0; 167*387f9dfdSAndroid Build Coastguard Worker 168*387f9dfdSAndroid Build Coastguard Worker struct bpf_pidns_info ns = {}; 169*387f9dfdSAndroid Build Coastguard Worker if (USE_PIDNS && !bpf_get_ns_current_pid_tgid(PIDNS_DEV, PIDNS_INO, &ns, sizeof(struct bpf_pidns_info))) { 170*387f9dfdSAndroid Build Coastguard Worker tgid = ns.tgid; 171*387f9dfdSAndroid Build Coastguard Worker pid = ns.pid; 172*387f9dfdSAndroid Build Coastguard Worker } else { 173*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid(); 174*387f9dfdSAndroid Build Coastguard Worker tgid = id >> 32; 175*387f9dfdSAndroid Build Coastguard Worker pid = id; 176*387f9dfdSAndroid Build Coastguard Worker } 177*387f9dfdSAndroid Build Coastguard Worker 178*387f9dfdSAndroid Build Coastguard Worker if (IDLE_FILTER) 179*387f9dfdSAndroid Build Coastguard Worker return 0; 180*387f9dfdSAndroid Build Coastguard Worker 181*387f9dfdSAndroid Build Coastguard Worker if (!(THREAD_FILTER)) 182*387f9dfdSAndroid Build Coastguard Worker return 0; 183*387f9dfdSAndroid Build Coastguard Worker 184*387f9dfdSAndroid Build Coastguard Worker if (container_should_be_filtered()) { 185*387f9dfdSAndroid Build Coastguard Worker return 0; 186*387f9dfdSAndroid Build Coastguard Worker } 187*387f9dfdSAndroid Build Coastguard Worker 188*387f9dfdSAndroid Build Coastguard Worker // create map key 189*387f9dfdSAndroid Build Coastguard Worker struct key_t key = {.pid = tgid}; 190*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&key.name, sizeof(key.name)); 191*387f9dfdSAndroid Build Coastguard Worker 192*387f9dfdSAndroid Build Coastguard Worker // get stacks 193*387f9dfdSAndroid Build Coastguard Worker key.user_stack_id = USER_STACK_GET; 194*387f9dfdSAndroid Build Coastguard Worker key.kernel_stack_id = KERNEL_STACK_GET; 195*387f9dfdSAndroid Build Coastguard Worker 196*387f9dfdSAndroid Build Coastguard Worker if (key.kernel_stack_id >= 0) { 197*387f9dfdSAndroid Build Coastguard Worker // populate extras to fix the kernel stack 198*387f9dfdSAndroid Build Coastguard Worker u64 ip = PT_REGS_IP(&ctx->regs); 199*387f9dfdSAndroid Build Coastguard Worker u64 page_offset; 200*387f9dfdSAndroid Build Coastguard Worker 201*387f9dfdSAndroid Build Coastguard Worker // if ip isn't sane, leave key ips as zero for later checking 202*387f9dfdSAndroid Build Coastguard Worker#if defined(CONFIG_X86_64) && defined(__PAGE_OFFSET_BASE) 203*387f9dfdSAndroid Build Coastguard Worker // x64, 4.16, ..., 4.11, etc., but some earlier kernel didn't have it 204*387f9dfdSAndroid Build Coastguard Worker page_offset = __PAGE_OFFSET_BASE; 205*387f9dfdSAndroid Build Coastguard Worker#elif defined(CONFIG_X86_64) && defined(__PAGE_OFFSET_BASE_L4) 206*387f9dfdSAndroid Build Coastguard Worker // x64, 4.17, and later 207*387f9dfdSAndroid Build Coastguard Worker#if defined(CONFIG_DYNAMIC_MEMORY_LAYOUT) && defined(CONFIG_X86_5LEVEL) 208*387f9dfdSAndroid Build Coastguard Worker page_offset = __PAGE_OFFSET_BASE_L5; 209*387f9dfdSAndroid Build Coastguard Worker#else 210*387f9dfdSAndroid Build Coastguard Worker page_offset = __PAGE_OFFSET_BASE_L4; 211*387f9dfdSAndroid Build Coastguard Worker#endif 212*387f9dfdSAndroid Build Coastguard Worker#else 213*387f9dfdSAndroid Build Coastguard Worker // earlier x86_64 kernels, e.g., 4.6, comes here 214*387f9dfdSAndroid Build Coastguard Worker // arm64, s390, powerpc, x86_32 215*387f9dfdSAndroid Build Coastguard Worker page_offset = PAGE_OFFSET; 216*387f9dfdSAndroid Build Coastguard Worker#endif 217*387f9dfdSAndroid Build Coastguard Worker 218*387f9dfdSAndroid Build Coastguard Worker if (ip > page_offset) { 219*387f9dfdSAndroid Build Coastguard Worker key.kernel_ip = ip; 220*387f9dfdSAndroid Build Coastguard Worker } 221*387f9dfdSAndroid Build Coastguard Worker } 222*387f9dfdSAndroid Build Coastguard Worker 223*387f9dfdSAndroid Build Coastguard Worker counts.increment(key); 224*387f9dfdSAndroid Build Coastguard Worker return 0; 225*387f9dfdSAndroid Build Coastguard Worker} 226*387f9dfdSAndroid Build Coastguard Worker""" 227*387f9dfdSAndroid Build Coastguard Worker 228*387f9dfdSAndroid Build Coastguard Worker# pid-namespace translation 229*387f9dfdSAndroid Build Coastguard Workertry: 230*387f9dfdSAndroid Build Coastguard Worker devinfo = os.stat("/proc/self/ns/pid") 231*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('USE_PIDNS', "1") 232*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PIDNS_DEV', str(devinfo.st_dev)) 233*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PIDNS_INO', str(devinfo.st_ino)) 234*387f9dfdSAndroid Build Coastguard Workerexcept: 235*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('USE_PIDNS', "0") 236*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PIDNS_DEV', "0") 237*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PIDNS_INO', "0") 238*387f9dfdSAndroid Build Coastguard Worker 239*387f9dfdSAndroid Build Coastguard Worker# set idle filter 240*387f9dfdSAndroid Build Coastguard Workeridle_filter = "pid == 0" 241*387f9dfdSAndroid Build Coastguard Workerif args.include_idle: 242*387f9dfdSAndroid Build Coastguard Worker idle_filter = "0" 243*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('IDLE_FILTER', idle_filter) 244*387f9dfdSAndroid Build Coastguard Worker 245*387f9dfdSAndroid Build Coastguard Worker# set process/thread filter 246*387f9dfdSAndroid Build Coastguard Workerthread_context = "" 247*387f9dfdSAndroid Build Coastguard Workerthread_filter = "" 248*387f9dfdSAndroid Build Coastguard Workerif args.pid is not None: 249*387f9dfdSAndroid Build Coastguard Worker thread_context = "PID %s" % args.pid 250*387f9dfdSAndroid Build Coastguard Worker thread_filter = " || ".join("tgid == " + str(pid) for pid in args.pid) 251*387f9dfdSAndroid Build Coastguard Workerelif args.tid is not None: 252*387f9dfdSAndroid Build Coastguard Worker thread_context = "TID %s" % args.tid 253*387f9dfdSAndroid Build Coastguard Worker thread_filter = " || ".join("pid == " + str(tid) for tid in args.tid) 254*387f9dfdSAndroid Build Coastguard Workerelse: 255*387f9dfdSAndroid Build Coastguard Worker thread_context = "all threads" 256*387f9dfdSAndroid Build Coastguard Worker thread_filter = '1' 257*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('THREAD_FILTER', thread_filter) 258*387f9dfdSAndroid Build Coastguard Worker 259*387f9dfdSAndroid Build Coastguard Worker# set stack storage size 260*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('HASH_STORAGE_SIZE', str(args.hash_storage_size)) 261*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('STACK_STORAGE_SIZE', str(args.stack_storage_size)) 262*387f9dfdSAndroid Build Coastguard Worker 263*387f9dfdSAndroid Build Coastguard Worker# handle stack args 264*387f9dfdSAndroid Build Coastguard Workerkernel_stack_get = "stack_traces.get_stackid(&ctx->regs, 0)" 265*387f9dfdSAndroid Build Coastguard Workeruser_stack_get = "stack_traces.get_stackid(&ctx->regs, BPF_F_USER_STACK)" 266*387f9dfdSAndroid Build Coastguard Workerstack_context = "" 267*387f9dfdSAndroid Build Coastguard Workerif args.user_stacks_only: 268*387f9dfdSAndroid Build Coastguard Worker stack_context = "user" 269*387f9dfdSAndroid Build Coastguard Worker kernel_stack_get = "-1" 270*387f9dfdSAndroid Build Coastguard Workerelif args.kernel_stacks_only: 271*387f9dfdSAndroid Build Coastguard Worker stack_context = "kernel" 272*387f9dfdSAndroid Build Coastguard Worker user_stack_get = "-1" 273*387f9dfdSAndroid Build Coastguard Workerelse: 274*387f9dfdSAndroid Build Coastguard Worker stack_context = "user + kernel" 275*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('USER_STACK_GET', user_stack_get) 276*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('KERNEL_STACK_GET', kernel_stack_get) 277*387f9dfdSAndroid Build Coastguard Workerbpf_text = filter_by_containers(args) + bpf_text 278*387f9dfdSAndroid Build Coastguard Worker 279*387f9dfdSAndroid Build Coastguard Workersample_freq = 0 280*387f9dfdSAndroid Build Coastguard Workersample_period = 0 281*387f9dfdSAndroid Build Coastguard Workerif args.frequency: 282*387f9dfdSAndroid Build Coastguard Worker sample_freq = args.frequency 283*387f9dfdSAndroid Build Coastguard Workerelif args.count: 284*387f9dfdSAndroid Build Coastguard Worker sample_period = args.count 285*387f9dfdSAndroid Build Coastguard Workerelse: 286*387f9dfdSAndroid Build Coastguard Worker # If user didn't specify anything, use default 49Hz sampling 287*387f9dfdSAndroid Build Coastguard Worker sample_freq = 49 288*387f9dfdSAndroid Build Coastguard Workersample_context = "%s%d %s" % (("", sample_freq, "Hertz") if sample_freq 289*387f9dfdSAndroid Build Coastguard Worker else ("every ", sample_period, "events")) 290*387f9dfdSAndroid Build Coastguard Worker 291*387f9dfdSAndroid Build Coastguard Worker# header 292*387f9dfdSAndroid Build Coastguard Workerif not args.folded: 293*387f9dfdSAndroid Build Coastguard Worker print("Sampling at %s of %s by %s stack" % 294*387f9dfdSAndroid Build Coastguard Worker (sample_context, thread_context, stack_context), end="") 295*387f9dfdSAndroid Build Coastguard Worker if args.cpu >= 0: 296*387f9dfdSAndroid Build Coastguard Worker print(" on CPU#{}".format(args.cpu), end="") 297*387f9dfdSAndroid Build Coastguard Worker if duration < 99999999: 298*387f9dfdSAndroid Build Coastguard Worker print(" for %d secs." % duration) 299*387f9dfdSAndroid Build Coastguard Worker else: 300*387f9dfdSAndroid Build Coastguard Worker print("... Hit Ctrl-C to end.") 301*387f9dfdSAndroid Build Coastguard Worker 302*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 303*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 304*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 305*387f9dfdSAndroid Build Coastguard Worker exit() 306*387f9dfdSAndroid Build Coastguard Worker 307*387f9dfdSAndroid Build Coastguard Worker# initialize BPF & perf_events 308*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 309*387f9dfdSAndroid Build Coastguard Workerb.attach_perf_event(ev_type=PerfType.SOFTWARE, 310*387f9dfdSAndroid Build Coastguard Worker ev_config=PerfSWConfig.CPU_CLOCK, fn_name="do_perf_event", 311*387f9dfdSAndroid Build Coastguard Worker sample_period=sample_period, sample_freq=sample_freq, cpu=args.cpu) 312*387f9dfdSAndroid Build Coastguard Worker 313*387f9dfdSAndroid Build Coastguard Worker# signal handler 314*387f9dfdSAndroid Build Coastguard Workerdef signal_ignore(signal, frame): 315*387f9dfdSAndroid Build Coastguard Worker print() 316*387f9dfdSAndroid Build Coastguard Worker 317*387f9dfdSAndroid Build Coastguard Worker# 318*387f9dfdSAndroid Build Coastguard Worker# Output Report 319*387f9dfdSAndroid Build Coastguard Worker# 320*387f9dfdSAndroid Build Coastguard Worker 321*387f9dfdSAndroid Build Coastguard Worker# collect samples 322*387f9dfdSAndroid Build Coastguard Workertry: 323*387f9dfdSAndroid Build Coastguard Worker sleep(duration) 324*387f9dfdSAndroid Build Coastguard Workerexcept KeyboardInterrupt: 325*387f9dfdSAndroid Build Coastguard Worker # as cleanup can take some time, trap Ctrl-C: 326*387f9dfdSAndroid Build Coastguard Worker signal.signal(signal.SIGINT, signal_ignore) 327*387f9dfdSAndroid Build Coastguard Worker 328*387f9dfdSAndroid Build Coastguard Workerif not args.folded: 329*387f9dfdSAndroid Build Coastguard Worker print() 330*387f9dfdSAndroid Build Coastguard Worker 331*387f9dfdSAndroid Build Coastguard Workerdef aksym(addr): 332*387f9dfdSAndroid Build Coastguard Worker if args.annotations: 333*387f9dfdSAndroid Build Coastguard Worker return b.ksym(addr) + "_[k]".encode() 334*387f9dfdSAndroid Build Coastguard Worker else: 335*387f9dfdSAndroid Build Coastguard Worker return b.ksym(addr) 336*387f9dfdSAndroid Build Coastguard Worker 337*387f9dfdSAndroid Build Coastguard Worker# output stacks 338*387f9dfdSAndroid Build Coastguard Workermissing_stacks = 0 339*387f9dfdSAndroid Build Coastguard Workerhas_collision = False 340*387f9dfdSAndroid Build Coastguard Workercounts = b.get_table("counts") 341*387f9dfdSAndroid Build Coastguard Workerhtab_full = args.hash_storage_size == len(counts) 342*387f9dfdSAndroid Build Coastguard Workerstack_traces = b.get_table("stack_traces") 343*387f9dfdSAndroid Build Coastguard Workerfor k, v in sorted(counts.items(), key=lambda counts: counts[1].value): 344*387f9dfdSAndroid Build Coastguard Worker # handle get_stackid errors 345*387f9dfdSAndroid Build Coastguard Worker if not args.user_stacks_only and stack_id_err(k.kernel_stack_id): 346*387f9dfdSAndroid Build Coastguard Worker missing_stacks += 1 347*387f9dfdSAndroid Build Coastguard Worker # hash collision (-EEXIST) suggests that the map size may be too small 348*387f9dfdSAndroid Build Coastguard Worker has_collision = has_collision or k.kernel_stack_id == -errno.EEXIST 349*387f9dfdSAndroid Build Coastguard Worker if not args.kernel_stacks_only and stack_id_err(k.user_stack_id): 350*387f9dfdSAndroid Build Coastguard Worker missing_stacks += 1 351*387f9dfdSAndroid Build Coastguard Worker has_collision = has_collision or k.user_stack_id == -errno.EEXIST 352*387f9dfdSAndroid Build Coastguard Worker 353*387f9dfdSAndroid Build Coastguard Worker user_stack = [] if k.user_stack_id < 0 else \ 354*387f9dfdSAndroid Build Coastguard Worker stack_traces.walk(k.user_stack_id) 355*387f9dfdSAndroid Build Coastguard Worker kernel_tmp = [] if k.kernel_stack_id < 0 else \ 356*387f9dfdSAndroid Build Coastguard Worker stack_traces.walk(k.kernel_stack_id) 357*387f9dfdSAndroid Build Coastguard Worker 358*387f9dfdSAndroid Build Coastguard Worker # fix kernel stack 359*387f9dfdSAndroid Build Coastguard Worker kernel_stack = [] 360*387f9dfdSAndroid Build Coastguard Worker if k.kernel_stack_id >= 0: 361*387f9dfdSAndroid Build Coastguard Worker for addr in kernel_tmp: 362*387f9dfdSAndroid Build Coastguard Worker kernel_stack.append(addr) 363*387f9dfdSAndroid Build Coastguard Worker # the later IP checking 364*387f9dfdSAndroid Build Coastguard Worker if k.kernel_ip: 365*387f9dfdSAndroid Build Coastguard Worker kernel_stack.insert(0, k.kernel_ip) 366*387f9dfdSAndroid Build Coastguard Worker 367*387f9dfdSAndroid Build Coastguard Worker if args.folded: 368*387f9dfdSAndroid Build Coastguard Worker # print folded stack output 369*387f9dfdSAndroid Build Coastguard Worker user_stack = list(user_stack) 370*387f9dfdSAndroid Build Coastguard Worker kernel_stack = list(kernel_stack) 371*387f9dfdSAndroid Build Coastguard Worker line = [k.name.decode('utf-8', 'replace')] 372*387f9dfdSAndroid Build Coastguard Worker # if we failed to get the stack is, such as due to no space (-ENOMEM) or 373*387f9dfdSAndroid Build Coastguard Worker # hash collision (-EEXIST), we still print a placeholder for consistency 374*387f9dfdSAndroid Build Coastguard Worker if not args.kernel_stacks_only: 375*387f9dfdSAndroid Build Coastguard Worker if stack_id_err(k.user_stack_id): 376*387f9dfdSAndroid Build Coastguard Worker line.append("[Missed User Stack]") 377*387f9dfdSAndroid Build Coastguard Worker else: 378*387f9dfdSAndroid Build Coastguard Worker line.extend([b.sym(addr, k.pid).decode('utf-8', 'replace') for addr in reversed(user_stack)]) 379*387f9dfdSAndroid Build Coastguard Worker if not args.user_stacks_only: 380*387f9dfdSAndroid Build Coastguard Worker line.extend(["-"] if (need_delimiter and k.kernel_stack_id >= 0 and k.user_stack_id >= 0) else []) 381*387f9dfdSAndroid Build Coastguard Worker if stack_id_err(k.kernel_stack_id): 382*387f9dfdSAndroid Build Coastguard Worker line.append("[Missed Kernel Stack]") 383*387f9dfdSAndroid Build Coastguard Worker else: 384*387f9dfdSAndroid Build Coastguard Worker line.extend([aksym(addr).decode('utf-8', 'replace') for addr in reversed(kernel_stack)]) 385*387f9dfdSAndroid Build Coastguard Worker print("%s %d" % (";".join(line), v.value)) 386*387f9dfdSAndroid Build Coastguard Worker else: 387*387f9dfdSAndroid Build Coastguard Worker # print default multi-line stack output 388*387f9dfdSAndroid Build Coastguard Worker if not args.user_stacks_only: 389*387f9dfdSAndroid Build Coastguard Worker if stack_id_err(k.kernel_stack_id): 390*387f9dfdSAndroid Build Coastguard Worker print(" [Missed Kernel Stack]") 391*387f9dfdSAndroid Build Coastguard Worker else: 392*387f9dfdSAndroid Build Coastguard Worker for addr in kernel_stack: 393*387f9dfdSAndroid Build Coastguard Worker print(" %s" % aksym(addr).decode('utf-8', 'replace')) 394*387f9dfdSAndroid Build Coastguard Worker if not args.kernel_stacks_only: 395*387f9dfdSAndroid Build Coastguard Worker if need_delimiter and k.user_stack_id >= 0 and k.kernel_stack_id >= 0: 396*387f9dfdSAndroid Build Coastguard Worker print(" --") 397*387f9dfdSAndroid Build Coastguard Worker if stack_id_err(k.user_stack_id): 398*387f9dfdSAndroid Build Coastguard Worker print(" [Missed User Stack]") 399*387f9dfdSAndroid Build Coastguard Worker else: 400*387f9dfdSAndroid Build Coastguard Worker for addr in user_stack: 401*387f9dfdSAndroid Build Coastguard Worker print(" %s" % b.sym(addr, k.pid).decode('utf-8', 'replace')) 402*387f9dfdSAndroid Build Coastguard Worker print(" %-16s %s (%d)" % ("-", k.name.decode('utf-8', 'replace'), k.pid)) 403*387f9dfdSAndroid Build Coastguard Worker print(" %d\n" % v.value) 404*387f9dfdSAndroid Build Coastguard Worker 405*387f9dfdSAndroid Build Coastguard Worker# check missing 406*387f9dfdSAndroid Build Coastguard Workerif missing_stacks > 0: 407*387f9dfdSAndroid Build Coastguard Worker enomem_str = "" if not has_collision else \ 408*387f9dfdSAndroid Build Coastguard Worker " Consider increasing --stack-storage-size." 409*387f9dfdSAndroid Build Coastguard Worker print("WARNING: %d stack traces could not be displayed.%s" % 410*387f9dfdSAndroid Build Coastguard Worker (missing_stacks, enomem_str), 411*387f9dfdSAndroid Build Coastguard Worker file=stderr) 412*387f9dfdSAndroid Build Coastguard Worker 413*387f9dfdSAndroid Build Coastguard Worker# check whether hash table is full 414*387f9dfdSAndroid Build Coastguard Workerif htab_full: 415*387f9dfdSAndroid Build Coastguard Worker print("WARNING: hash table full. Consider increasing --hash-storage-size.", 416*387f9dfdSAndroid Build Coastguard Worker file=stderr) 417