1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# hardirqs Summarize hard 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: hardirqs [-h] [-T] [-N] [-C] [-d] [interval] [outputs] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# Thanks Amer Ather for help understanding irq behavior. 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2015 Brendan Gregg. 12*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 13*387f9dfdSAndroid Build Coastguard Worker# 14*387f9dfdSAndroid Build Coastguard Worker# 19-Oct-2015 Brendan Gregg Created this. 15*387f9dfdSAndroid Build Coastguard Worker 16*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 17*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 18*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 19*387f9dfdSAndroid Build Coastguard Workerimport argparse 20*387f9dfdSAndroid Build Coastguard Worker 21*387f9dfdSAndroid Build Coastguard Worker# arguments 22*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 23*387f9dfdSAndroid Build Coastguard Worker ./hardirqs # sum hard irq event time 24*387f9dfdSAndroid Build Coastguard Worker ./hardirqs -d # show hard irq event time as histograms 25*387f9dfdSAndroid Build Coastguard Worker ./hardirqs 1 10 # print 1 second summaries, 10 times 26*387f9dfdSAndroid Build Coastguard Worker ./hardirqs -NT 1 # 1s summaries, nanoseconds, and timestamps 27*387f9dfdSAndroid Build Coastguard Worker""" 28*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 29*387f9dfdSAndroid Build Coastguard Worker description="Summarize hard irq event time as histograms", 30*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 31*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 32*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--timestamp", action="store_true", 33*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output") 34*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-N", "--nanoseconds", action="store_true", 35*387f9dfdSAndroid Build Coastguard Worker help="output in nanoseconds") 36*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-C", "--count", action="store_true", 37*387f9dfdSAndroid Build Coastguard Worker help="show event counts instead of timing") 38*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--dist", action="store_true", 39*387f9dfdSAndroid Build Coastguard Worker help="show distributions as histograms") 40*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=99999999, 41*387f9dfdSAndroid Build Coastguard Worker help="output interval, in seconds") 42*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("outputs", nargs="?", default=99999999, 43*387f9dfdSAndroid Build Coastguard Worker help="number of outputs") 44*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 45*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 46*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 47*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.outputs) 48*387f9dfdSAndroid Build Coastguard Workerif args.count and (args.dist or args.nanoseconds): 49*387f9dfdSAndroid Build Coastguard Worker print("The --count option can't be used with time-based options") 50*387f9dfdSAndroid Build Coastguard Worker exit() 51*387f9dfdSAndroid Build Coastguard Workerif args.count: 52*387f9dfdSAndroid Build Coastguard Worker factor = 1 53*387f9dfdSAndroid Build Coastguard Worker label = "count" 54*387f9dfdSAndroid Build Coastguard Workerelif args.nanoseconds: 55*387f9dfdSAndroid Build Coastguard Worker factor = 1 56*387f9dfdSAndroid Build Coastguard Worker label = "nsecs" 57*387f9dfdSAndroid Build Coastguard Workerelse: 58*387f9dfdSAndroid Build Coastguard Worker factor = 1000 59*387f9dfdSAndroid Build Coastguard Worker label = "usecs" 60*387f9dfdSAndroid Build Coastguard Workerdebug = 0 61*387f9dfdSAndroid Build Coastguard Worker 62*387f9dfdSAndroid Build Coastguard Worker# define BPF program 63*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 64*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 65*387f9dfdSAndroid Build Coastguard Worker#include <linux/irq.h> 66*387f9dfdSAndroid Build Coastguard Worker#include <linux/irqdesc.h> 67*387f9dfdSAndroid Build Coastguard Worker#include <linux/interrupt.h> 68*387f9dfdSAndroid Build Coastguard Worker 69*387f9dfdSAndroid Build Coastguard Workertypedef struct irq_key { 70*387f9dfdSAndroid Build Coastguard Worker char name[32]; 71*387f9dfdSAndroid Build Coastguard Worker u64 slot; 72*387f9dfdSAndroid Build Coastguard Worker} irq_key_t; 73*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, u32); 74*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(irqdesc, u32, struct irq_desc *); 75*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(dist, irq_key_t); 76*387f9dfdSAndroid Build Coastguard Worker 77*387f9dfdSAndroid Build Coastguard Worker// count IRQ 78*387f9dfdSAndroid Build Coastguard Workerint count_only(struct pt_regs *ctx, struct irq_desc *desc) 79*387f9dfdSAndroid Build Coastguard Worker{ 80*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid(); 81*387f9dfdSAndroid Build Coastguard Worker 82*387f9dfdSAndroid Build Coastguard Worker struct irqaction *action = desc->action; 83*387f9dfdSAndroid Build Coastguard Worker char *name = (char *)action->name; 84*387f9dfdSAndroid Build Coastguard Worker 85*387f9dfdSAndroid Build Coastguard Worker irq_key_t key = {.slot = 0 /* ignore */}; 86*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&key.name, sizeof(key.name), name); 87*387f9dfdSAndroid Build Coastguard Worker dist.increment(key); 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard Worker return 0; 90*387f9dfdSAndroid Build Coastguard Worker} 91*387f9dfdSAndroid Build Coastguard Worker 92*387f9dfdSAndroid Build Coastguard Worker// time IRQ 93*387f9dfdSAndroid Build Coastguard Workerint trace_start(struct pt_regs *ctx, struct irq_desc *desc) 94*387f9dfdSAndroid Build Coastguard Worker{ 95*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid(); 96*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns(); 97*387f9dfdSAndroid Build Coastguard Worker start.update(&pid, &ts); 98*387f9dfdSAndroid Build Coastguard Worker irqdesc.update(&pid, &desc); 99*387f9dfdSAndroid Build Coastguard Worker return 0; 100*387f9dfdSAndroid Build Coastguard Worker} 101*387f9dfdSAndroid Build Coastguard Worker 102*387f9dfdSAndroid Build Coastguard Workerint trace_completion(struct pt_regs *ctx) 103*387f9dfdSAndroid Build Coastguard Worker{ 104*387f9dfdSAndroid Build Coastguard Worker u64 *tsp, delta; 105*387f9dfdSAndroid Build Coastguard Worker struct irq_desc **descp; 106*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid(); 107*387f9dfdSAndroid Build Coastguard Worker 108*387f9dfdSAndroid Build Coastguard Worker // fetch timestamp and calculate delta 109*387f9dfdSAndroid Build Coastguard Worker tsp = start.lookup(&pid); 110*387f9dfdSAndroid Build Coastguard Worker descp = irqdesc.lookup(&pid); 111*387f9dfdSAndroid Build Coastguard Worker if (tsp == 0 || descp == 0) { 112*387f9dfdSAndroid Build Coastguard Worker return 0; // missed start 113*387f9dfdSAndroid Build Coastguard Worker } 114*387f9dfdSAndroid Build Coastguard Worker struct irq_desc *desc = *descp; 115*387f9dfdSAndroid Build Coastguard Worker struct irqaction *action = desc->action; 116*387f9dfdSAndroid Build Coastguard Worker char *name = (char *)action->name; 117*387f9dfdSAndroid Build Coastguard Worker delta = bpf_ktime_get_ns() - *tsp; 118*387f9dfdSAndroid Build Coastguard Worker 119*387f9dfdSAndroid Build Coastguard Worker // store as sum or histogram 120*387f9dfdSAndroid Build Coastguard Worker STORE 121*387f9dfdSAndroid Build Coastguard Worker 122*387f9dfdSAndroid Build Coastguard Worker start.delete(&pid); 123*387f9dfdSAndroid Build Coastguard Worker irqdesc.delete(&pid); 124*387f9dfdSAndroid Build Coastguard Worker return 0; 125*387f9dfdSAndroid Build Coastguard Worker} 126*387f9dfdSAndroid Build Coastguard Worker""" 127*387f9dfdSAndroid Build Coastguard Worker 128*387f9dfdSAndroid Build Coastguard Worker# code substitutions 129*387f9dfdSAndroid Build Coastguard Workerif args.dist: 130*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE', 131*387f9dfdSAndroid Build Coastguard Worker 'irq_key_t key = {.slot = bpf_log2l(delta / %d)};' % factor + 132*387f9dfdSAndroid Build Coastguard Worker 'bpf_probe_read_kernel(&key.name, sizeof(key.name), name);' + 133*387f9dfdSAndroid Build Coastguard Worker 'dist.increment(key);') 134*387f9dfdSAndroid Build Coastguard Workerelse: 135*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE', 136*387f9dfdSAndroid Build Coastguard Worker 'irq_key_t key = {.slot = 0 /* ignore */};' + 137*387f9dfdSAndroid Build Coastguard Worker 'bpf_probe_read_kernel(&key.name, sizeof(key.name), name);' + 138*387f9dfdSAndroid Build Coastguard Worker 'dist.increment(key, delta);') 139*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 140*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 141*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 142*387f9dfdSAndroid Build Coastguard Worker exit() 143*387f9dfdSAndroid Build Coastguard Worker 144*387f9dfdSAndroid Build Coastguard Worker# load BPF program 145*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 146*387f9dfdSAndroid Build Coastguard Worker 147*387f9dfdSAndroid Build Coastguard Worker# these should really use irq:irq_handler_entry/exit tracepoints: 148*387f9dfdSAndroid Build Coastguard Workerif args.count: 149*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="handle_irq_event_percpu", fn_name="count_only") 150*387f9dfdSAndroid Build Coastguard Worker print("Tracing hard irq events... Hit Ctrl-C to end.") 151*387f9dfdSAndroid Build Coastguard Workerelse: 152*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="handle_irq_event_percpu", fn_name="trace_start") 153*387f9dfdSAndroid Build Coastguard Worker b.attach_kretprobe(event="handle_irq_event_percpu", 154*387f9dfdSAndroid Build Coastguard Worker fn_name="trace_completion") 155*387f9dfdSAndroid Build Coastguard Worker print("Tracing hard irq event time... Hit Ctrl-C to end.") 156*387f9dfdSAndroid Build Coastguard Worker 157*387f9dfdSAndroid Build Coastguard Worker# output 158*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1 159*387f9dfdSAndroid Build Coastguard Workerdist = b.get_table("dist") 160*387f9dfdSAndroid Build Coastguard Workerwhile (1): 161*387f9dfdSAndroid Build Coastguard Worker try: 162*387f9dfdSAndroid Build Coastguard Worker sleep(int(args.interval)) 163*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 164*387f9dfdSAndroid Build Coastguard Worker exiting = 1 165*387f9dfdSAndroid Build Coastguard Worker 166*387f9dfdSAndroid Build Coastguard Worker print() 167*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 168*387f9dfdSAndroid Build Coastguard Worker print("%-8s\n" % strftime("%H:%M:%S"), end="") 169*387f9dfdSAndroid Build Coastguard Worker 170*387f9dfdSAndroid Build Coastguard Worker if args.dist: 171*387f9dfdSAndroid Build Coastguard Worker dist.print_log2_hist(label, "hardirq") 172*387f9dfdSAndroid Build Coastguard Worker else: 173*387f9dfdSAndroid Build Coastguard Worker print("%-26s %11s" % ("HARDIRQ", "TOTAL_" + label)) 174*387f9dfdSAndroid Build Coastguard Worker for k, v in sorted(dist.items(), key=lambda dist: dist[1].value): 175*387f9dfdSAndroid Build Coastguard Worker print("%-26s %11d" % (k.name.decode('utf-8', 'replace'), v.value / factor)) 176*387f9dfdSAndroid Build Coastguard Worker dist.clear() 177*387f9dfdSAndroid Build Coastguard Worker 178*387f9dfdSAndroid Build Coastguard Worker countdown -= 1 179*387f9dfdSAndroid Build Coastguard Worker if exiting or countdown == 0: 180*387f9dfdSAndroid Build Coastguard Worker exit() 181