xref: /aosp_15_r20/external/bcc/tools/softirqs.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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