1 /* Copyright (c) 2016 Facebook
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
7 #include <uapi/linux/bpf.h>
8 #include "bpf_helpers.h"
9 #include <uapi/linux/ptrace.h>
10 #include <uapi/linux/perf_event.h>
11 #include <linux/version.h>
12 #include <linux/sched.h>
14 #define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
19 char waker
[TASK_COMM_LEN
];
20 char target
[TASK_COMM_LEN
];
25 struct bpf_map_def
SEC("maps") counts
= {
26 .type
= BPF_MAP_TYPE_HASH
,
27 .key_size
= sizeof(struct key_t
),
28 .value_size
= sizeof(u64
),
32 struct bpf_map_def
SEC("maps") start
= {
33 .type
= BPF_MAP_TYPE_HASH
,
34 .key_size
= sizeof(u32
),
35 .value_size
= sizeof(u64
),
40 char name
[TASK_COMM_LEN
];
44 struct bpf_map_def
SEC("maps") wokeby
= {
45 .type
= BPF_MAP_TYPE_HASH
,
46 .key_size
= sizeof(u32
),
47 .value_size
= sizeof(struct wokeby_t
),
51 struct bpf_map_def
SEC("maps") stackmap
= {
52 .type
= BPF_MAP_TYPE_STACK_TRACE
,
53 .key_size
= sizeof(u32
),
54 .value_size
= PERF_MAX_STACK_DEPTH
* sizeof(u64
),
58 #define STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP)
60 SEC("kprobe/try_to_wake_up")
61 int waker(struct pt_regs
*ctx
)
63 struct task_struct
*p
= (void *) PT_REGS_PARM1(ctx
);
64 struct wokeby_t woke
= {};
69 bpf_get_current_comm(&woke
.name
, sizeof(woke
.name
));
70 woke
.ret
= bpf_get_stackid(ctx
, &stackmap
, STACKID_FLAGS
);
72 bpf_map_update_elem(&wokeby
, &pid
, &woke
, BPF_ANY
);
76 static inline int update_counts(struct pt_regs
*ctx
, u32 pid
, u64 delta
)
78 struct key_t key
= {};
79 struct wokeby_t
*woke
;
82 bpf_get_current_comm(&key
.target
, sizeof(key
.target
));
83 key
.tret
= bpf_get_stackid(ctx
, &stackmap
, STACKID_FLAGS
);
85 woke
= bpf_map_lookup_elem(&wokeby
, &pid
);
88 __builtin_memcpy(&key
.waker
, woke
->name
, TASK_COMM_LEN
);
89 bpf_map_delete_elem(&wokeby
, &pid
);
92 val
= bpf_map_lookup_elem(&counts
, &key
);
94 bpf_map_update_elem(&counts
, &key
, &zero
, BPF_NOEXIST
);
95 val
= bpf_map_lookup_elem(&counts
, &key
);
103 SEC("kprobe/finish_task_switch")
104 int oncpu(struct pt_regs
*ctx
)
106 struct task_struct
*p
= (void *) PT_REGS_PARM1(ctx
);
110 /* record previous thread sleep time */
112 ts
= bpf_ktime_get_ns();
113 bpf_map_update_elem(&start
, &pid
, &ts
, BPF_ANY
);
115 /* calculate current thread's delta time */
116 pid
= bpf_get_current_pid_tgid();
117 tsp
= bpf_map_lookup_elem(&start
, &pid
);
119 /* missed start or filtered */
122 delta
= bpf_ktime_get_ns() - *tsp
;
123 bpf_map_delete_elem(&start
, &pid
);
124 delta
= delta
/ 1000;
125 if (delta
< MINBLOCK_US
)
128 return update_counts(ctx
, pid
, delta
);
130 char _license
[] SEC("license") = "GPL";
131 u32 _version
SEC("version") = LINUX_VERSION_CODE
;