blob: 6a5da031fcfee539a5555d378bb725d814d0928d [file] [log] [blame]
Brendan Gregg860b6492015-10-20 15:52:23 -07001#!/usr/bin/python
Alexei Starovoitovbdf07732016-01-14 10:09:20 -08002# @lint-avoid-python-3-compatibility-imports
Brendan Gregg860b6492015-10-20 15:52:23 -07003#
Alexei Starovoitovbdf07732016-01-14 10:09:20 -08004# hardirqs Summarize hard IRQ (interrupt) event time.
5# For Linux, uses BCC, eBPF.
Brendan Gregg860b6492015-10-20 15:52:23 -07006#
Brendan Greggc32b8452017-11-26 23:38:32 -08007# USAGE: hardirqs [-h] [-T] [-N] [-C] [-d] [interval] [outputs]
Brendan Gregg860b6492015-10-20 15:52:23 -07008#
9# Thanks Amer Ather for help understanding irq behavior.
10#
11# Copyright (c) 2015 Brendan Gregg.
12# Licensed under the Apache License, Version 2.0 (the "License")
13#
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080014# 19-Oct-2015 Brendan Gregg Created this.
Brendan Gregg860b6492015-10-20 15:52:23 -070015
16from __future__ import print_function
17from bcc import BPF
18from time import sleep, strftime
19import argparse
20
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030021# arguments
Brendan Gregg860b6492015-10-20 15:52:23 -070022examples = """examples:
23 ./hardirqs # sum hard irq event time
24 ./hardirqs -d # show hard irq event time as histograms
25 ./hardirqs 1 10 # print 1 second summaries, 10 times
26 ./hardirqs -NT 1 # 1s summaries, nanoseconds, and timestamps
27"""
28parser = argparse.ArgumentParser(
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080029 description="Summarize hard irq event time as histograms",
30 formatter_class=argparse.RawDescriptionHelpFormatter,
31 epilog=examples)
Brendan Gregg860b6492015-10-20 15:52:23 -070032parser.add_argument("-T", "--timestamp", action="store_true",
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080033 help="include timestamp on output")
Brendan Gregg860b6492015-10-20 15:52:23 -070034parser.add_argument("-N", "--nanoseconds", action="store_true",
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080035 help="output in nanoseconds")
Brendan Greggc32b8452017-11-26 23:38:32 -080036parser.add_argument("-C", "--count", action="store_true",
37 help="show event counts instead of timing")
Brendan Gregg860b6492015-10-20 15:52:23 -070038parser.add_argument("-d", "--dist", action="store_true",
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080039 help="show distributions as histograms")
Brendan Gregg860b6492015-10-20 15:52:23 -070040parser.add_argument("interval", nargs="?", default=99999999,
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080041 help="output interval, in seconds")
Brendan Greggc32b8452017-11-26 23:38:32 -080042parser.add_argument("outputs", nargs="?", default=99999999,
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080043 help="number of outputs")
Nathan Scottcf0792f2018-02-02 16:56:50 +110044parser.add_argument("--ebpf", action="store_true",
45 help=argparse.SUPPRESS)
Brendan Gregg860b6492015-10-20 15:52:23 -070046args = parser.parse_args()
Brendan Greggc32b8452017-11-26 23:38:32 -080047countdown = int(args.outputs)
48if args.count and (args.dist or args.nanoseconds):
49 print("The --count option can't be used with time-based options")
50 exit()
51if args.count:
52 factor = 1
53 label = "count"
54elif args.nanoseconds:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080055 factor = 1
56 label = "nsecs"
Brendan Gregg860b6492015-10-20 15:52:23 -070057else:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080058 factor = 1000
59 label = "usecs"
Brendan Gregg860b6492015-10-20 15:52:23 -070060debug = 0
61
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030062# define BPF program
Brendan Gregg860b6492015-10-20 15:52:23 -070063bpf_text = """
64#include <uapi/linux/ptrace.h>
65#include <linux/irq.h>
66#include <linux/irqdesc.h>
67#include <linux/interrupt.h>
68
69typedef struct irq_key {
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080070 char name[32];
71 u64 slot;
Brendan Gregg860b6492015-10-20 15:52:23 -070072} irq_key_t;
73BPF_HASH(start, u32);
74BPF_HASH(irqdesc, u32, struct irq_desc *);
75BPF_HISTOGRAM(dist, irq_key_t);
76
Brendan Greggc32b8452017-11-26 23:38:32 -080077// count IRQ
78int count_only(struct pt_regs *ctx, struct irq_desc *desc)
79{
80 u32 pid = bpf_get_current_pid_tgid();
81
82 struct irqaction *action = desc->action;
83 char *name = (char *)action->name;
84
85 irq_key_t key = {.slot = 0 /* ignore */};
86 bpf_probe_read(&key.name, sizeof(key.name), name);
87 u64 zero = 0, *vp = dist.lookup_or_init(&key, &zero);
88 (*vp)++;
89
90 return 0;
91}
92
Brendan Gregg860b6492015-10-20 15:52:23 -070093// time IRQ
94int trace_start(struct pt_regs *ctx, struct irq_desc *desc)
95{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080096 u32 pid = bpf_get_current_pid_tgid();
97 u64 ts = bpf_ktime_get_ns();
98 start.update(&pid, &ts);
99 irqdesc.update(&pid, &desc);
100 return 0;
Brendan Gregg860b6492015-10-20 15:52:23 -0700101}
102
103int trace_completion(struct pt_regs *ctx)
104{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800105 u64 *tsp, delta;
106 struct irq_desc **descp;
107 u32 pid = bpf_get_current_pid_tgid();
Brendan Gregg860b6492015-10-20 15:52:23 -0700108
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800109 // fetch timestamp and calculate delta
110 tsp = start.lookup(&pid);
111 descp = irqdesc.lookup(&pid);
112 if (tsp == 0 || descp == 0) {
113 return 0; // missed start
114 }
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200115 struct irq_desc *desc = *descp;
116 struct irqaction *action = desc->action;
117 char *name = (char *)action->name;
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800118 delta = bpf_ktime_get_ns() - *tsp;
Brendan Gregg860b6492015-10-20 15:52:23 -0700119
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800120 // store as sum or histogram
121 STORE
Brendan Gregg860b6492015-10-20 15:52:23 -0700122
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800123 start.delete(&pid);
124 irqdesc.delete(&pid);
125 return 0;
Brendan Gregg860b6492015-10-20 15:52:23 -0700126}
127"""
128
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300129# code substitutions
Brendan Gregg860b6492015-10-20 15:52:23 -0700130if args.dist:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800131 bpf_text = bpf_text.replace('STORE',
Kirill Smelkovf2d125e2017-09-25 11:23:03 +0300132 'irq_key_t key = {.slot = bpf_log2l(delta / %d)};' % factor +
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800133 'bpf_probe_read(&key.name, sizeof(key.name), name);' +
134 'dist.increment(key);')
Brendan Gregg860b6492015-10-20 15:52:23 -0700135else:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800136 bpf_text = bpf_text.replace('STORE',
137 'irq_key_t key = {.slot = 0 /* ignore */};' +
138 'bpf_probe_read(&key.name, sizeof(key.name), name);' +
139 'u64 zero = 0, *vp = dist.lookup_or_init(&key, &zero);' +
140 '(*vp) += delta;')
Nathan Scottcf0792f2018-02-02 16:56:50 +1100141if debug or args.ebpf:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800142 print(bpf_text)
Nathan Scottcf0792f2018-02-02 16:56:50 +1100143 if args.ebpf:
144 exit()
Brendan Gregg860b6492015-10-20 15:52:23 -0700145
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300146# load BPF program
Brendan Gregg860b6492015-10-20 15:52:23 -0700147b = BPF(text=bpf_text)
148
149# these should really use irq:irq_handler_entry/exit tracepoints:
Brendan Greggc32b8452017-11-26 23:38:32 -0800150if args.count:
151 b.attach_kprobe(event="handle_irq_event_percpu", fn_name="count_only")
152 print("Tracing hard irq events... Hit Ctrl-C to end.")
153else:
154 b.attach_kprobe(event="handle_irq_event_percpu", fn_name="trace_start")
155 b.attach_kretprobe(event="handle_irq_event_percpu",
156 fn_name="trace_completion")
157 print("Tracing hard irq event time... Hit Ctrl-C to end.")
Brendan Gregg860b6492015-10-20 15:52:23 -0700158
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300159# output
Brendan Gregg860b6492015-10-20 15:52:23 -0700160exiting = 0 if args.interval else 1
161dist = b.get_table("dist")
162while (1):
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800163 try:
164 sleep(int(args.interval))
165 except KeyboardInterrupt:
166 exiting = 1
Brendan Gregg860b6492015-10-20 15:52:23 -0700167
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800168 print()
169 if args.timestamp:
170 print("%-8s\n" % strftime("%H:%M:%S"), end="")
Brendan Gregg860b6492015-10-20 15:52:23 -0700171
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800172 if args.dist:
173 dist.print_log2_hist(label, "hardirq")
174 else:
175 print("%-26s %11s" % ("HARDIRQ", "TOTAL_" + label))
176 for k, v in sorted(dist.items(), key=lambda dist: dist[1].value):
Rafael F78948e42017-03-26 14:54:25 +0200177 print("%-26s %11d" % (k.name.decode(), v.value / factor))
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800178 dist.clear()
Brendan Gregg860b6492015-10-20 15:52:23 -0700179
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800180 countdown -= 1
181 if exiting or countdown == 0:
182 exit()