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# softirqs Summarize soft IRQ (interrupt) event time. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: softirqs [-h] [-T] [-N] [-C] [-d] [-c CPU] [interval] [count] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2015 Brendan Gregg. 10*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 11*387f9dfdSAndroid Build Coastguard Worker# 12*387f9dfdSAndroid Build Coastguard Worker# 20-Oct-2015 Brendan Gregg Created this. 13*387f9dfdSAndroid Build Coastguard Worker# 03-Apr-2017 Sasha Goldshtein Migrated to kernel tracepoints. 14*387f9dfdSAndroid Build Coastguard Worker# 07-Mar-2022 Rocky Xing Added CPU filter support. 15*387f9dfdSAndroid Build Coastguard Worker# 24-Mar-2022 Rocky Xing Added event counting support. 16*387f9dfdSAndroid Build Coastguard Worker 17*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 18*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 19*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 20*387f9dfdSAndroid Build Coastguard Workerimport argparse 21*387f9dfdSAndroid Build Coastguard Workerimport sys 22*387f9dfdSAndroid Build Coastguard Worker 23*387f9dfdSAndroid Build Coastguard Worker# arguments 24*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 25*387f9dfdSAndroid Build Coastguard Worker ./softirqs # sum soft irq event time 26*387f9dfdSAndroid Build Coastguard Worker ./softirqs -C # show the number of soft irq events 27*387f9dfdSAndroid Build Coastguard Worker ./softirqs -d # show soft irq event time as histograms 28*387f9dfdSAndroid Build Coastguard Worker ./softirqs 1 10 # print 1 second summaries, 10 times 29*387f9dfdSAndroid Build Coastguard Worker ./softirqs -NT 1 # 1s summaries, nanoseconds, and timestamps 30*387f9dfdSAndroid Build Coastguard Worker ./softirqs -c 1 # sum soft irq event time on CPU 1 only 31*387f9dfdSAndroid Build Coastguard Worker""" 32*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 33*387f9dfdSAndroid Build Coastguard Worker description="Summarize soft irq event time as histograms.", 34*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 35*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 36*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--timestamp", action="store_true", 37*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output") 38*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-N", "--nanoseconds", action="store_true", 39*387f9dfdSAndroid Build Coastguard Worker help="output in nanoseconds") 40*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-C", "--events", action="store_true", 41*387f9dfdSAndroid Build Coastguard Worker help="show the number of soft irq events") 42*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--dist", action="store_true", 43*387f9dfdSAndroid Build Coastguard Worker help="show distributions as histograms") 44*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-c", "--cpu", type=int, 45*387f9dfdSAndroid Build Coastguard Worker help="trace this CPU only") 46*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=99999999, 47*387f9dfdSAndroid Build Coastguard Worker help="output interval, in seconds") 48*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999, 49*387f9dfdSAndroid Build Coastguard Worker help="number of outputs") 50*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 51*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 52*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 53*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.count) 54*387f9dfdSAndroid Build Coastguard Workerif args.events and (args.dist or args.nanoseconds): 55*387f9dfdSAndroid Build Coastguard Worker print("The --events option can't be used with time-based options") 56*387f9dfdSAndroid Build Coastguard Worker exit() 57*387f9dfdSAndroid Build Coastguard Workerif args.events: 58*387f9dfdSAndroid Build Coastguard Worker factor = 1 59*387f9dfdSAndroid Build Coastguard Worker label = "count" 60*387f9dfdSAndroid Build Coastguard Workerelif args.nanoseconds: 61*387f9dfdSAndroid Build Coastguard Worker factor = 1 62*387f9dfdSAndroid Build Coastguard Worker label = "nsecs" 63*387f9dfdSAndroid Build Coastguard Workerelse: 64*387f9dfdSAndroid Build Coastguard Worker factor = 1000 65*387f9dfdSAndroid Build Coastguard Worker label = "usecs" 66*387f9dfdSAndroid Build Coastguard Workerdebug = 0 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Worker# define BPF program 69*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 70*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 71*387f9dfdSAndroid Build Coastguard Worker 72*387f9dfdSAndroid Build Coastguard Workertypedef struct entry_key { 73*387f9dfdSAndroid Build Coastguard Worker u32 pid; 74*387f9dfdSAndroid Build Coastguard Worker u32 cpu; 75*387f9dfdSAndroid Build Coastguard Worker} entry_key_t; 76*387f9dfdSAndroid Build Coastguard Worker 77*387f9dfdSAndroid Build Coastguard Workertypedef struct irq_key { 78*387f9dfdSAndroid Build Coastguard Worker u32 vec; 79*387f9dfdSAndroid Build Coastguard Worker u64 slot; 80*387f9dfdSAndroid Build Coastguard Worker} irq_key_t; 81*387f9dfdSAndroid Build Coastguard Worker 82*387f9dfdSAndroid Build Coastguard Workertypedef struct account_val { 83*387f9dfdSAndroid Build Coastguard Worker u64 ts; 84*387f9dfdSAndroid Build Coastguard Worker u32 vec; 85*387f9dfdSAndroid Build Coastguard Worker} account_val_t; 86*387f9dfdSAndroid Build Coastguard Worker 87*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, entry_key_t, account_val_t); 88*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(dist, irq_key_t); 89*387f9dfdSAndroid Build Coastguard Worker""" 90*387f9dfdSAndroid Build Coastguard Worker 91*387f9dfdSAndroid Build Coastguard Workerbpf_text_count = """ 92*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(irq, softirq_entry) 93*387f9dfdSAndroid Build Coastguard Worker{ 94*387f9dfdSAndroid Build Coastguard Worker u32 cpu = bpf_get_smp_processor_id(); 95*387f9dfdSAndroid Build Coastguard Worker 96*387f9dfdSAndroid Build Coastguard Worker FILTER_CPU 97*387f9dfdSAndroid Build Coastguard Worker 98*387f9dfdSAndroid Build Coastguard Worker irq_key_t key = { .slot = 0 /* ignore */ }; 99*387f9dfdSAndroid Build Coastguard Worker key.vec = args->vec; 100*387f9dfdSAndroid Build Coastguard Worker 101*387f9dfdSAndroid Build Coastguard Worker dist.atomic_increment(key); 102*387f9dfdSAndroid Build Coastguard Worker 103*387f9dfdSAndroid Build Coastguard Worker return 0; 104*387f9dfdSAndroid Build Coastguard Worker} 105*387f9dfdSAndroid Build Coastguard Worker""" 106*387f9dfdSAndroid Build Coastguard Worker 107*387f9dfdSAndroid Build Coastguard Workerbpf_text_time = """ 108*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(irq, softirq_entry) 109*387f9dfdSAndroid Build Coastguard Worker{ 110*387f9dfdSAndroid Build Coastguard Worker account_val_t val = {}; 111*387f9dfdSAndroid Build Coastguard Worker entry_key_t key = {}; 112*387f9dfdSAndroid Build Coastguard Worker u32 cpu = bpf_get_smp_processor_id(); 113*387f9dfdSAndroid Build Coastguard Worker 114*387f9dfdSAndroid Build Coastguard Worker FILTER_CPU 115*387f9dfdSAndroid Build Coastguard Worker 116*387f9dfdSAndroid Build Coastguard Worker key.pid = bpf_get_current_pid_tgid(); 117*387f9dfdSAndroid Build Coastguard Worker key.cpu = cpu; 118*387f9dfdSAndroid Build Coastguard Worker val.ts = bpf_ktime_get_ns(); 119*387f9dfdSAndroid Build Coastguard Worker val.vec = args->vec; 120*387f9dfdSAndroid Build Coastguard Worker 121*387f9dfdSAndroid Build Coastguard Worker start.update(&key, &val); 122*387f9dfdSAndroid Build Coastguard Worker 123*387f9dfdSAndroid Build Coastguard Worker return 0; 124*387f9dfdSAndroid Build Coastguard Worker} 125*387f9dfdSAndroid Build Coastguard Worker 126*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(irq, softirq_exit) 127*387f9dfdSAndroid Build Coastguard Worker{ 128*387f9dfdSAndroid Build Coastguard Worker u64 delta; 129*387f9dfdSAndroid Build Coastguard Worker u32 vec; 130*387f9dfdSAndroid Build Coastguard Worker account_val_t *valp; 131*387f9dfdSAndroid Build Coastguard Worker irq_key_t key = {0}; 132*387f9dfdSAndroid Build Coastguard Worker entry_key_t entry_key = {}; 133*387f9dfdSAndroid Build Coastguard Worker u32 cpu = bpf_get_smp_processor_id(); 134*387f9dfdSAndroid Build Coastguard Worker 135*387f9dfdSAndroid Build Coastguard Worker FILTER_CPU 136*387f9dfdSAndroid Build Coastguard Worker 137*387f9dfdSAndroid Build Coastguard Worker entry_key.pid = bpf_get_current_pid_tgid(); 138*387f9dfdSAndroid Build Coastguard Worker entry_key.cpu = cpu; 139*387f9dfdSAndroid Build Coastguard Worker 140*387f9dfdSAndroid Build Coastguard Worker // fetch timestamp and calculate delta 141*387f9dfdSAndroid Build Coastguard Worker valp = start.lookup(&entry_key); 142*387f9dfdSAndroid Build Coastguard Worker if (valp == 0) { 143*387f9dfdSAndroid Build Coastguard Worker return 0; // missed start 144*387f9dfdSAndroid Build Coastguard Worker } 145*387f9dfdSAndroid Build Coastguard Worker delta = bpf_ktime_get_ns() - valp->ts; 146*387f9dfdSAndroid Build Coastguard Worker vec = valp->vec; 147*387f9dfdSAndroid Build Coastguard Worker 148*387f9dfdSAndroid Build Coastguard Worker // store as sum or histogram 149*387f9dfdSAndroid Build Coastguard Worker STORE 150*387f9dfdSAndroid Build Coastguard Worker 151*387f9dfdSAndroid Build Coastguard Worker start.delete(&entry_key); 152*387f9dfdSAndroid Build Coastguard Worker return 0; 153*387f9dfdSAndroid Build Coastguard Worker} 154*387f9dfdSAndroid Build Coastguard Worker""" 155*387f9dfdSAndroid Build Coastguard Worker 156*387f9dfdSAndroid Build Coastguard Workerif args.events: 157*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_count 158*387f9dfdSAndroid Build Coastguard Workerelse: 159*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_time 160*387f9dfdSAndroid Build Coastguard Worker 161*387f9dfdSAndroid Build Coastguard Worker# code substitutions 162*387f9dfdSAndroid Build Coastguard Workerif args.dist: 163*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE', 164*387f9dfdSAndroid Build Coastguard Worker 'key.vec = vec; key.slot = bpf_log2l(delta / %d); ' % factor + 165*387f9dfdSAndroid Build Coastguard Worker 'dist.atomic_increment(key);') 166*387f9dfdSAndroid Build Coastguard Workerelse: 167*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE', 168*387f9dfdSAndroid Build Coastguard Worker 'key.vec = valp->vec; ' + 169*387f9dfdSAndroid Build Coastguard Worker 'dist.atomic_increment(key, delta);') 170*387f9dfdSAndroid Build Coastguard Workerif args.cpu is not None: 171*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_CPU', 172*387f9dfdSAndroid Build Coastguard Worker 'if (cpu != %d) { return 0; }' % int(args.cpu)) 173*387f9dfdSAndroid Build Coastguard Workerelse: 174*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_CPU', '') 175*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 176*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 177*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 178*387f9dfdSAndroid Build Coastguard Worker exit() 179*387f9dfdSAndroid Build Coastguard Worker 180*387f9dfdSAndroid Build Coastguard Worker# load BPF program 181*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 182*387f9dfdSAndroid Build Coastguard Worker 183*387f9dfdSAndroid Build Coastguard Workerdef vec_to_name(vec): 184*387f9dfdSAndroid Build Coastguard Worker # copied from softirq_to_name() in kernel/softirq.c 185*387f9dfdSAndroid Build Coastguard Worker # may need updates if new softirq handlers are added 186*387f9dfdSAndroid Build Coastguard Worker return ["hi", "timer", "net_tx", "net_rx", "block", "irq_poll", 187*387f9dfdSAndroid Build Coastguard Worker "tasklet", "sched", "hrtimer", "rcu"][vec] 188*387f9dfdSAndroid Build Coastguard Worker 189*387f9dfdSAndroid Build Coastguard Workerif args.events: 190*387f9dfdSAndroid Build Coastguard Worker print("Tracing soft irq events... Hit Ctrl-C to end.") 191*387f9dfdSAndroid Build Coastguard Workerelse: 192*387f9dfdSAndroid Build Coastguard Worker print("Tracing soft irq event time... Hit Ctrl-C to end.") 193*387f9dfdSAndroid Build Coastguard Worker 194*387f9dfdSAndroid Build Coastguard Worker# output 195*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1 196*387f9dfdSAndroid Build Coastguard Workerdist = b.get_table("dist") 197*387f9dfdSAndroid Build Coastguard Workerwhile (1): 198*387f9dfdSAndroid Build Coastguard Worker try: 199*387f9dfdSAndroid Build Coastguard Worker sleep(int(args.interval)) 200*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 201*387f9dfdSAndroid Build Coastguard Worker exiting = 1 202*387f9dfdSAndroid Build Coastguard Worker 203*387f9dfdSAndroid Build Coastguard Worker print() 204*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 205*387f9dfdSAndroid Build Coastguard Worker print("%-8s\n" % strftime("%H:%M:%S"), end="") 206*387f9dfdSAndroid Build Coastguard Worker 207*387f9dfdSAndroid Build Coastguard Worker if args.dist: 208*387f9dfdSAndroid Build Coastguard Worker dist.print_log2_hist(label, "softirq", section_print_fn=vec_to_name) 209*387f9dfdSAndroid Build Coastguard Worker else: 210*387f9dfdSAndroid Build Coastguard Worker print("%-16s %11s" % ("SOFTIRQ", "TOTAL_" + label)) 211*387f9dfdSAndroid Build Coastguard Worker for k, v in sorted(dist.items(), key=lambda dist: dist[1].value): 212*387f9dfdSAndroid Build Coastguard Worker print("%-16s %11d" % (vec_to_name(k.vec), v.value / factor)) 213*387f9dfdSAndroid Build Coastguard Worker dist.clear() 214*387f9dfdSAndroid Build Coastguard Worker 215*387f9dfdSAndroid Build Coastguard Worker sys.stdout.flush() 216*387f9dfdSAndroid Build Coastguard Worker 217*387f9dfdSAndroid Build Coastguard Worker countdown -= 1 218*387f9dfdSAndroid Build Coastguard Worker if exiting or countdown == 0: 219*387f9dfdSAndroid Build Coastguard Worker exit() 220