1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Wenbo Zhang
3 #include <vmlinux.h>
4 #include <bpf/bpf_core_read.h>
5 #include <bpf/bpf_helpers.h>
6 #include <bpf/bpf_tracing.h>
7 #include "hardirqs.h"
8 #include "bits.bpf.h"
9 #include "maps.bpf.h"
10
11 #define MAX_ENTRIES 256
12
13 const volatile bool filter_cg = false;
14 const volatile bool targ_dist = false;
15 const volatile bool targ_ns = false;
16 const volatile bool do_count = false;
17
18 struct {
19 __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
20 __type(key, u32);
21 __type(value, u32);
22 __uint(max_entries, 1);
23 } cgroup_map SEC(".maps");
24
25 struct {
26 __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
27 __uint(max_entries, 1);
28 __type(key, u32);
29 __type(value, u64);
30 } start SEC(".maps");
31
32 struct {
33 __uint(type, BPF_MAP_TYPE_HASH);
34 __uint(max_entries, MAX_ENTRIES);
35 __type(key, struct irq_key);
36 __type(value, struct info);
37 } infos SEC(".maps");
38
39 static struct info zero;
40
handle_entry(int irq,struct irqaction * action)41 static int handle_entry(int irq, struct irqaction *action)
42 {
43 if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
44 return 0;
45
46 if (do_count) {
47 struct irq_key key = {};
48 struct info *info;
49
50 bpf_probe_read_kernel_str(&key.name, sizeof(key.name), BPF_CORE_READ(action, name));
51 info = bpf_map_lookup_or_try_init(&infos, &key, &zero);
52 if (!info)
53 return 0;
54 info->count += 1;
55 return 0;
56 } else {
57 u64 ts = bpf_ktime_get_ns();
58 u32 key = 0;
59
60 if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
61 return 0;
62
63 bpf_map_update_elem(&start, &key, &ts, BPF_ANY);
64 return 0;
65 }
66 }
67
handle_exit(int irq,struct irqaction * action)68 static int handle_exit(int irq, struct irqaction *action)
69 {
70 struct irq_key ikey = {};
71 struct info *info;
72 u32 key = 0;
73 u64 delta;
74 u64 *tsp;
75
76 if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
77 return 0;
78
79 tsp = bpf_map_lookup_elem(&start, &key);
80 if (!tsp)
81 return 0;
82
83 delta = bpf_ktime_get_ns() - *tsp;
84 if (!targ_ns)
85 delta /= 1000U;
86
87 bpf_probe_read_kernel_str(&ikey.name, sizeof(ikey.name), BPF_CORE_READ(action, name));
88 info = bpf_map_lookup_or_try_init(&infos, &ikey, &zero);
89 if (!info)
90 return 0;
91
92 if (!targ_dist) {
93 info->count += delta;
94 } else {
95 u64 slot;
96
97 slot = log2(delta);
98 if (slot >= MAX_SLOTS)
99 slot = MAX_SLOTS - 1;
100 info->slots[slot]++;
101 }
102
103 return 0;
104 }
105
106 SEC("tp_btf/irq_handler_entry")
BPF_PROG(irq_handler_entry_btf,int irq,struct irqaction * action)107 int BPF_PROG(irq_handler_entry_btf, int irq, struct irqaction *action)
108 {
109 return handle_entry(irq, action);
110 }
111
112 SEC("tp_btf/irq_handler_exit")
BPF_PROG(irq_handler_exit_btf,int irq,struct irqaction * action)113 int BPF_PROG(irq_handler_exit_btf, int irq, struct irqaction *action)
114 {
115 return handle_exit(irq, action);
116 }
117
118 SEC("raw_tp/irq_handler_entry")
BPF_PROG(irq_handler_entry,int irq,struct irqaction * action)119 int BPF_PROG(irq_handler_entry, int irq, struct irqaction *action)
120 {
121 return handle_entry(irq, action);
122 }
123
124 SEC("raw_tp/irq_handler_exit")
BPF_PROG(irq_handler_exit,int irq,struct irqaction * action)125 int BPF_PROG(irq_handler_exit, int irq, struct irqaction *action)
126 {
127 return handle_exit(irq, action);
128 }
129
130 char LICENSE[] SEC("license") = "GPL";
131