Skip to content

Instantly share code, notes, and snippets.

@brendangregg
Created October 19, 2015 20:44
Show Gist options
  • Save brendangregg/a4a2c19b6206e205d540 to your computer and use it in GitHub Desktop.
Save brendangregg/a4a2c19b6206e205d540 to your computer and use it in GitHub Desktop.
irqdist
#!/usr/bin/python
#
# irqdist Summarize irq event time as a histogram.
# For Linux, uses BCC, eBPF.
#
# USAGE: irqdist [-h] [-T] [-Q] [-m] [-D] [interval] [count]
#
# Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License")
#
# 19-Oct-2015 Brendan Gregg Created this.
from __future__ import print_function
from bcc import BPF
from time import sleep, strftime
import argparse
### arguments
examples = """examples:
./irqdist # summarize irq event time as histograms
./irqdist 1 10 # print 1 second summaries, 10 times
./irqdist -mT 1 # 1s summaries, milliseconds, and timestamps
"""
parser = argparse.ArgumentParser(
description="Summarize irq event time as histograms",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples)
parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output")
parser.add_argument("-m", "--milliseconds", action="store_true",
help="millisecond histogram")
parser.add_argument("interval", nargs="?", default=99999999,
help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=99999999,
help="number of outputs")
args = parser.parse_args()
countdown = int(args.count)
debug = 0
### define BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <linux/interrupt.h>
typedef struct irq_key {
char name[32];
u64 slot;
} irq_key_t;
BPF_HASH(start, u32);
BPF_HASH(irqdesc, u32, struct irq_desc *);
BPF_HISTOGRAM(dist, irq_key_t);
// time IRQ
int trace_start(struct pt_regs *ctx, struct irq_desc *desc)
{
u32 pid = bpf_get_current_pid_tgid();
u64 ts = bpf_ktime_get_ns();
start.update(&pid, &ts);
irqdesc.update(&pid, &desc);
return 0;
}
int trace_completion(struct pt_regs *ctx)
{
u64 *tsp, delta;
struct irq_desc **descp;
u32 pid = bpf_get_current_pid_tgid();
// fetch timestamp and calculate delta
tsp = start.lookup(&pid);
descp = irqdesc.lookup(&pid);
if (tsp == 0 || descp == 0) {
return 0; // missed start
}
delta = bpf_ktime_get_ns() - *tsp;
FACTOR
// store as histogram
irq_key_t key = {.slot = bpf_log2l(delta)};
struct irq_desc *desc = *descp;
bpf_probe_read(&key.name, sizeof(key.name), (void *)desc->name);
dist.increment(key);
start.delete(&pid);
irqdesc.delete(&pid);
return 0;
}
"""
### code substitutions
if args.milliseconds:
bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000000;')
label = "msecs"
else:
bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000;')
label = "usecs"
if debug:
print(bpf_text)
### load BPF program
b = BPF(text=bpf_text)
# these should really use irq:irq_handler_entry/exit tracepoints:
b.attach_kprobe(event="handle_irq_event_percpu", fn_name="trace_start")
b.attach_kretprobe(event="handle_irq_event_percpu", fn_name="trace_completion")
print("Tracing irq event time... Hit Ctrl-C to end.")
### output
exiting = 0 if args.interval else 1
dist = b.get_table("dist")
while (1):
try:
sleep(int(args.interval))
except KeyboardInterrupt:
exiting=1
print()
if args.timestamp:
print("%-8s\n" % strftime("%H:%M:%S"), end="")
dist.print_log2_hist(label, "interrupt")
dist.clear()
countdown -= 1
if exiting or countdown == 0:
exit()
@drzaeus77
Copy link

@@ -70,12 +70,18 @@ int trace_completion(struct pt_regs *ctx
        if (tsp == 0 || descp == 0) {
                return 0;       // missed start
        }
+       // Note: descp is a value from map, so '&' can be done without
+       // probe_read, but the next level char * needs a probe read.
+       // Do these steps first after reading the map, otherwise some of these
+       // pointers may get pushed onto the stack and verifier will fail.
+       const char **namep = &(*descp)->name;
+       char *name = 0;
+       bpf_probe_read(&name, sizeof(name), namep);
        delta = bpf_ktime_get_ns() - *tsp;
        FACTOR
        // store as histogram
        irq_key_t key = {.slot = bpf_log2l(delta)};
-       struct irq_desc *desc = *descp;
-       bpf_probe_read(&key.name, sizeof(key.name), (void *)desc->name);
+       bpf_probe_read(&key.name, sizeof(key.name), name);
        dist.increment(key);
        start.delete(&pid);
        irqdesc.delete(&pid);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment