0001
0002
0003
0004
0005
0006
0007 #include <uapi/linux/bpf.h>
0008 #include <uapi/linux/ptrace.h>
0009 #include <uapi/linux/perf_event.h>
0010 #include <linux/version.h>
0011 #include <linux/sched.h>
0012 #include <bpf/bpf_helpers.h>
0013 #include <bpf/bpf_tracing.h>
0014
0015 #define _(P) \
0016 ({ \
0017 typeof(P) val; \
0018 bpf_probe_read_kernel(&val, sizeof(val), &(P)); \
0019 val; \
0020 })
0021
0022 #define MINBLOCK_US 1
0023 #define MAX_ENTRIES 10000
0024
0025 struct key_t {
0026 char waker[TASK_COMM_LEN];
0027 char target[TASK_COMM_LEN];
0028 u32 wret;
0029 u32 tret;
0030 };
0031
0032 struct {
0033 __uint(type, BPF_MAP_TYPE_HASH);
0034 __type(key, struct key_t);
0035 __type(value, u64);
0036 __uint(max_entries, MAX_ENTRIES);
0037 } counts SEC(".maps");
0038
0039 struct {
0040 __uint(type, BPF_MAP_TYPE_HASH);
0041 __type(key, u32);
0042 __type(value, u64);
0043 __uint(max_entries, MAX_ENTRIES);
0044 } start SEC(".maps");
0045
0046 struct wokeby_t {
0047 char name[TASK_COMM_LEN];
0048 u32 ret;
0049 };
0050
0051 struct {
0052 __uint(type, BPF_MAP_TYPE_HASH);
0053 __type(key, u32);
0054 __type(value, struct wokeby_t);
0055 __uint(max_entries, MAX_ENTRIES);
0056 } wokeby SEC(".maps");
0057
0058 struct {
0059 __uint(type, BPF_MAP_TYPE_STACK_TRACE);
0060 __uint(key_size, sizeof(u32));
0061 __uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64));
0062 __uint(max_entries, MAX_ENTRIES);
0063 } stackmap SEC(".maps");
0064
0065 #define STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP)
0066
0067 SEC("kprobe/try_to_wake_up")
0068 int waker(struct pt_regs *ctx)
0069 {
0070 struct task_struct *p = (void *) PT_REGS_PARM1(ctx);
0071 struct wokeby_t woke;
0072 u32 pid;
0073
0074 pid = _(p->pid);
0075
0076 bpf_get_current_comm(&woke.name, sizeof(woke.name));
0077 woke.ret = bpf_get_stackid(ctx, &stackmap, STACKID_FLAGS);
0078
0079 bpf_map_update_elem(&wokeby, &pid, &woke, BPF_ANY);
0080 return 0;
0081 }
0082
0083 static inline int update_counts(void *ctx, u32 pid, u64 delta)
0084 {
0085 struct wokeby_t *woke;
0086 u64 zero = 0, *val;
0087 struct key_t key;
0088
0089 __builtin_memset(&key.waker, 0, sizeof(key.waker));
0090 bpf_get_current_comm(&key.target, sizeof(key.target));
0091 key.tret = bpf_get_stackid(ctx, &stackmap, STACKID_FLAGS);
0092 key.wret = 0;
0093
0094 woke = bpf_map_lookup_elem(&wokeby, &pid);
0095 if (woke) {
0096 key.wret = woke->ret;
0097 __builtin_memcpy(&key.waker, woke->name, sizeof(key.waker));
0098 bpf_map_delete_elem(&wokeby, &pid);
0099 }
0100
0101 val = bpf_map_lookup_elem(&counts, &key);
0102 if (!val) {
0103 bpf_map_update_elem(&counts, &key, &zero, BPF_NOEXIST);
0104 val = bpf_map_lookup_elem(&counts, &key);
0105 if (!val)
0106 return 0;
0107 }
0108 (*val) += delta;
0109 return 0;
0110 }
0111
0112 #if 1
0113
0114 struct sched_switch_args {
0115 unsigned long long pad;
0116 char prev_comm[TASK_COMM_LEN];
0117 int prev_pid;
0118 int prev_prio;
0119 long long prev_state;
0120 char next_comm[TASK_COMM_LEN];
0121 int next_pid;
0122 int next_prio;
0123 };
0124 SEC("tracepoint/sched/sched_switch")
0125 int oncpu(struct sched_switch_args *ctx)
0126 {
0127
0128 u32 pid = ctx->prev_pid;
0129 #else
0130 SEC("kprobe/finish_task_switch")
0131 int oncpu(struct pt_regs *ctx)
0132 {
0133 struct task_struct *p = (void *) PT_REGS_PARM1(ctx);
0134
0135 u32 pid = _(p->pid);
0136 #endif
0137 u64 delta, ts, *tsp;
0138
0139 ts = bpf_ktime_get_ns();
0140 bpf_map_update_elem(&start, &pid, &ts, BPF_ANY);
0141
0142
0143 pid = bpf_get_current_pid_tgid();
0144 tsp = bpf_map_lookup_elem(&start, &pid);
0145 if (!tsp)
0146
0147 return 0;
0148
0149 delta = bpf_ktime_get_ns() - *tsp;
0150 bpf_map_delete_elem(&start, &pid);
0151 delta = delta / 1000;
0152 if (delta < MINBLOCK_US)
0153 return 0;
0154
0155 return update_counts(ctx, pid, delta);
0156 }
0157 char _license[] SEC("license") = "GPL";
0158 u32 _version SEC("version") = LINUX_VERSION_CODE;