• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# @lint-avoid-python-3-compatibility-imports
3#
4# softirqs  Summarize soft IRQ (interrupt) event time.
5#           For Linux, uses BCC, eBPF.
6#
7# USAGE: softirqs [-h] [-T] [-N] [-d] [interval] [count]
8#
9# Copyright (c) 2015 Brendan Gregg.
10# Licensed under the Apache License, Version 2.0 (the "License")
11#
12# 20-Oct-2015   Brendan Gregg     Created this.
13# 03-Apr-2017   Sasha Goldshtein  Migrated to kernel tracepoints.
14
15from __future__ import print_function
16from bcc import BPF
17from time import sleep, strftime
18import argparse
19
20# arguments
21examples = """examples:
22    ./softirqs            # sum soft irq event time
23    ./softirqs -d         # show soft irq event time as histograms
24    ./softirqs 1 10       # print 1 second summaries, 10 times
25    ./softirqs -NT 1      # 1s summaries, nanoseconds, and timestamps
26"""
27parser = argparse.ArgumentParser(
28    description="Summarize soft irq event time as histograms.",
29    formatter_class=argparse.RawDescriptionHelpFormatter,
30    epilog=examples)
31parser.add_argument("-T", "--timestamp", action="store_true",
32    help="include timestamp on output")
33parser.add_argument("-N", "--nanoseconds", action="store_true",
34    help="output in nanoseconds")
35parser.add_argument("-d", "--dist", action="store_true",
36    help="show distributions as histograms")
37parser.add_argument("interval", nargs="?", default=99999999,
38    help="output interval, in seconds")
39parser.add_argument("count", nargs="?", default=99999999,
40    help="number of outputs")
41parser.add_argument("--ebpf", action="store_true",
42    help=argparse.SUPPRESS)
43args = parser.parse_args()
44countdown = int(args.count)
45if args.nanoseconds:
46    factor = 1
47    label = "nsecs"
48else:
49    factor = 1000
50    label = "usecs"
51debug = 0
52
53# define BPF program
54bpf_text = """
55#include <uapi/linux/ptrace.h>
56
57typedef struct irq_key {
58    u32 vec;
59    u64 slot;
60} irq_key_t;
61
62typedef struct account_val {
63    u64 ts;
64    u32 vec;
65} account_val_t;
66
67BPF_HASH(start, u32, account_val_t);
68BPF_HASH(iptr, u32);
69BPF_HISTOGRAM(dist, irq_key_t);
70
71TRACEPOINT_PROBE(irq, softirq_entry)
72{
73    u32 pid = bpf_get_current_pid_tgid();
74    account_val_t val = {};
75    val.ts = bpf_ktime_get_ns();
76    val.vec = args->vec;
77    start.update(&pid, &val);
78    return 0;
79}
80
81TRACEPOINT_PROBE(irq, softirq_exit)
82{
83    u64 delta;
84    u32 vec;
85    u32 pid = bpf_get_current_pid_tgid();
86    account_val_t *valp;
87    irq_key_t key = {0};
88
89    // fetch timestamp and calculate delta
90    valp = start.lookup(&pid);
91    if (valp == 0) {
92        return 0;   // missed start
93    }
94    delta = bpf_ktime_get_ns() - valp->ts;
95    vec = valp->vec;
96
97    // store as sum or histogram
98    STORE
99
100    start.delete(&pid);
101    return 0;
102}
103"""
104
105# code substitutions
106if args.dist:
107    bpf_text = bpf_text.replace('STORE',
108        'key.vec = vec; key.slot = bpf_log2l(delta / %d); ' % factor +
109        'dist.increment(key);')
110else:
111    bpf_text = bpf_text.replace('STORE',
112        'key.vec = valp->vec; ' +
113        'dist.increment(key, delta);')
114if debug or args.ebpf:
115    print(bpf_text)
116    if args.ebpf:
117        exit()
118
119# load BPF program
120b = BPF(text=bpf_text)
121
122def vec_to_name(vec):
123    # copied from softirq_to_name() in kernel/softirq.c
124    # may need updates if new softirq handlers are added
125    return ["hi", "timer", "net_tx", "net_rx", "block", "irq_poll",
126            "tasklet", "sched", "hrtimer", "rcu"][vec]
127
128print("Tracing soft irq event time... Hit Ctrl-C to end.")
129
130# output
131exiting = 0 if args.interval else 1
132dist = b.get_table("dist")
133while (1):
134    try:
135        sleep(int(args.interval))
136    except KeyboardInterrupt:
137        exiting = 1
138
139    print()
140    if args.timestamp:
141        print("%-8s\n" % strftime("%H:%M:%S"), end="")
142
143    if args.dist:
144        dist.print_log2_hist(label, "softirq", section_print_fn=vec_to_name)
145    else:
146        print("%-16s %11s" % ("SOFTIRQ", "TOTAL_" + label))
147        for k, v in sorted(dist.items(), key=lambda dist: dist[1].value):
148            print("%-16s %11d" % (vec_to_name(k.vec), v.value / factor))
149    dist.clear()
150
151    countdown -= 1
152    if exiting or countdown == 0:
153        exit()
154