blob: 3835d635e2e48c98963e9655e52081d335aca90f [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);
Javier Honduvilla Coto64bf9652018-08-01 06:50:19 +020087 dist.increment(key);
Brendan Greggc32b8452017-11-26 23:38:32 -080088
89 return 0;
90}
91
Brendan Gregg860b6492015-10-20 15:52:23 -070092// time IRQ
93int trace_start(struct pt_regs *ctx, struct irq_desc *desc)
94{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080095 u32 pid = bpf_get_current_pid_tgid();
96 u64 ts = bpf_ktime_get_ns();
97 start.update(&pid, &ts);
98 irqdesc.update(&pid, &desc);
99 return 0;
Brendan Gregg860b6492015-10-20 15:52:23 -0700100}
101
102int trace_completion(struct pt_regs *ctx)
103{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800104 u64 *tsp, delta;
105 struct irq_desc **descp;
106 u32 pid = bpf_get_current_pid_tgid();
Brendan Gregg860b6492015-10-20 15:52:23 -0700107
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800108 // fetch timestamp and calculate delta
109 tsp = start.lookup(&pid);
110 descp = irqdesc.lookup(&pid);
111 if (tsp == 0 || descp == 0) {
112 return 0; // missed start
113 }
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200114 struct irq_desc *desc = *descp;
115 struct irqaction *action = desc->action;
116 char *name = (char *)action->name;
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800117 delta = bpf_ktime_get_ns() - *tsp;
Brendan Gregg860b6492015-10-20 15:52:23 -0700118
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800119 // store as sum or histogram
120 STORE
Brendan Gregg860b6492015-10-20 15:52:23 -0700121
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800122 start.delete(&pid);
123 irqdesc.delete(&pid);
124 return 0;
Brendan Gregg860b6492015-10-20 15:52:23 -0700125}
126"""
127
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300128# code substitutions
Brendan Gregg860b6492015-10-20 15:52:23 -0700129if args.dist:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800130 bpf_text = bpf_text.replace('STORE',
Kirill Smelkovf2d125e2017-09-25 11:23:03 +0300131 'irq_key_t key = {.slot = bpf_log2l(delta / %d)};' % factor +
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800132 'bpf_probe_read(&key.name, sizeof(key.name), name);' +
133 'dist.increment(key);')
Brendan Gregg860b6492015-10-20 15:52:23 -0700134else:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800135 bpf_text = bpf_text.replace('STORE',
136 'irq_key_t key = {.slot = 0 /* ignore */};' +
137 'bpf_probe_read(&key.name, sizeof(key.name), name);' +
Javier Honduvilla Coto64bf9652018-08-01 06:50:19 +0200138 'dist.increment(key, delta);')
Nathan Scottcf0792f2018-02-02 16:56:50 +1100139if debug or args.ebpf:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800140 print(bpf_text)
Nathan Scottcf0792f2018-02-02 16:56:50 +1100141 if args.ebpf:
142 exit()
Brendan Gregg860b6492015-10-20 15:52:23 -0700143
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300144# load BPF program
Brendan Gregg860b6492015-10-20 15:52:23 -0700145b = BPF(text=bpf_text)
146
147# these should really use irq:irq_handler_entry/exit tracepoints:
Brendan Greggc32b8452017-11-26 23:38:32 -0800148if args.count:
149 b.attach_kprobe(event="handle_irq_event_percpu", fn_name="count_only")
150 print("Tracing hard irq events... Hit Ctrl-C to end.")
151else:
152 b.attach_kprobe(event="handle_irq_event_percpu", fn_name="trace_start")
153 b.attach_kretprobe(event="handle_irq_event_percpu",
154 fn_name="trace_completion")
155 print("Tracing hard irq event time... Hit Ctrl-C to end.")
Brendan Gregg860b6492015-10-20 15:52:23 -0700156
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300157# output
Brendan Gregg860b6492015-10-20 15:52:23 -0700158exiting = 0 if args.interval else 1
159dist = b.get_table("dist")
160while (1):
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800161 try:
162 sleep(int(args.interval))
163 except KeyboardInterrupt:
164 exiting = 1
Brendan Gregg860b6492015-10-20 15:52:23 -0700165
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800166 print()
167 if args.timestamp:
168 print("%-8s\n" % strftime("%H:%M:%S"), end="")
Brendan Gregg860b6492015-10-20 15:52:23 -0700169
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800170 if args.dist:
171 dist.print_log2_hist(label, "hardirq")
172 else:
173 print("%-26s %11s" % ("HARDIRQ", "TOTAL_" + label))
174 for k, v in sorted(dist.items(), key=lambda dist: dist[1].value):
Rafael F78948e42017-03-26 14:54:25 +0200175 print("%-26s %11d" % (k.name.decode(), v.value / factor))
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800176 dist.clear()
Brendan Gregg860b6492015-10-20 15:52:23 -0700177
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800178 countdown -= 1
179 if exiting or countdown == 0:
180 exit()