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 <uapi/linux/ptrace.h>
9 #include <uapi/linux/perf_event.h>
10 #include <linux/version.h>
11 #include <linux/sched.h>
12 #include <bpf/bpf_helpers.h>
13 #include <bpf/bpf_tracing.h>
18 bpf_probe_read_kernel(&val, sizeof(val), &(P)); \
25 char waker
[TASK_COMM_LEN
];
26 char target
[TASK_COMM_LEN
];
31 struct bpf_map_def
SEC("maps") counts
= {
32 .type
= BPF_MAP_TYPE_HASH
,
33 .key_size
= sizeof(struct key_t
),
34 .value_size
= sizeof(u64
),
38 struct bpf_map_def
SEC("maps") start
= {
39 .type
= BPF_MAP_TYPE_HASH
,
40 .key_size
= sizeof(u32
),
41 .value_size
= sizeof(u64
),
46 char name
[TASK_COMM_LEN
];
50 struct bpf_map_def
SEC("maps") wokeby
= {
51 .type
= BPF_MAP_TYPE_HASH
,
52 .key_size
= sizeof(u32
),
53 .value_size
= sizeof(struct wokeby_t
),
57 struct bpf_map_def
SEC("maps") stackmap
= {
58 .type
= BPF_MAP_TYPE_STACK_TRACE
,
59 .key_size
= sizeof(u32
),
60 .value_size
= PERF_MAX_STACK_DEPTH
* sizeof(u64
),
64 #define STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP)
66 SEC("kprobe/try_to_wake_up")
67 int waker(struct pt_regs
*ctx
)
69 struct task_struct
*p
= (void *) PT_REGS_PARM1(ctx
);
75 bpf_get_current_comm(&woke
.name
, sizeof(woke
.name
));
76 woke
.ret
= bpf_get_stackid(ctx
, &stackmap
, STACKID_FLAGS
);
78 bpf_map_update_elem(&wokeby
, &pid
, &woke
, BPF_ANY
);
82 static inline int update_counts(void *ctx
, u32 pid
, u64 delta
)
84 struct wokeby_t
*woke
;
88 __builtin_memset(&key
.waker
, 0, sizeof(key
.waker
));
89 bpf_get_current_comm(&key
.target
, sizeof(key
.target
));
90 key
.tret
= bpf_get_stackid(ctx
, &stackmap
, STACKID_FLAGS
);
93 woke
= bpf_map_lookup_elem(&wokeby
, &pid
);
96 __builtin_memcpy(&key
.waker
, woke
->name
, sizeof(key
.waker
));
97 bpf_map_delete_elem(&wokeby
, &pid
);
100 val
= bpf_map_lookup_elem(&counts
, &key
);
102 bpf_map_update_elem(&counts
, &key
, &zero
, BPF_NOEXIST
);
103 val
= bpf_map_lookup_elem(&counts
, &key
);
112 /* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */
113 struct sched_switch_args
{
114 unsigned long long pad
;
118 long long prev_state
;
123 SEC("tracepoint/sched/sched_switch")
124 int oncpu(struct sched_switch_args
*ctx
)
126 /* record previous thread sleep time */
127 u32 pid
= ctx
->prev_pid
;
129 SEC("kprobe/finish_task_switch")
130 int oncpu(struct pt_regs
*ctx
)
132 struct task_struct
*p
= (void *) PT_REGS_PARM1(ctx
);
133 /* record previous thread sleep time */
138 ts
= bpf_ktime_get_ns();
139 bpf_map_update_elem(&start
, &pid
, &ts
, BPF_ANY
);
141 /* calculate current thread's delta time */
142 pid
= bpf_get_current_pid_tgid();
143 tsp
= bpf_map_lookup_elem(&start
, &pid
);
145 /* missed start or filtered */
148 delta
= bpf_ktime_get_ns() - *tsp
;
149 bpf_map_delete_elem(&start
, &pid
);
150 delta
= delta
/ 1000;
151 if (delta
< MINBLOCK_US
)
154 return update_counts(ctx
, pid
, delta
);
156 char _license
[] SEC("license") = "GPL";
157 u32 _version
SEC("version") = LINUX_VERSION_CODE
;