1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2021 Wenbo Zhang
3*387f9dfdSAndroid Build Coastguard Worker #include <vmlinux.h>
4*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_helpers.h>
5*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_core_read.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_tracing.h>
7*387f9dfdSAndroid Build Coastguard Worker #include "offcputime.h"
8*387f9dfdSAndroid Build Coastguard Worker #include "core_fixes.bpf.h"
9*387f9dfdSAndroid Build Coastguard Worker
10*387f9dfdSAndroid Build Coastguard Worker #define PF_KTHREAD 0x00200000 /* I am a kernel thread */
11*387f9dfdSAndroid Build Coastguard Worker #define MAX_ENTRIES 10240
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Worker const volatile bool kernel_threads_only = false;
14*387f9dfdSAndroid Build Coastguard Worker const volatile bool user_threads_only = false;
15*387f9dfdSAndroid Build Coastguard Worker const volatile __u64 max_block_ns = -1;
16*387f9dfdSAndroid Build Coastguard Worker const volatile __u64 min_block_ns = 1;
17*387f9dfdSAndroid Build Coastguard Worker const volatile pid_t targ_tgid = -1;
18*387f9dfdSAndroid Build Coastguard Worker const volatile pid_t targ_pid = -1;
19*387f9dfdSAndroid Build Coastguard Worker const volatile long state = -1;
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Worker struct internal_key {
22*387f9dfdSAndroid Build Coastguard Worker u64 start_ts;
23*387f9dfdSAndroid Build Coastguard Worker struct key_t key;
24*387f9dfdSAndroid Build Coastguard Worker };
25*387f9dfdSAndroid Build Coastguard Worker
26*387f9dfdSAndroid Build Coastguard Worker struct {
27*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_HASH);
28*387f9dfdSAndroid Build Coastguard Worker __type(key, u32);
29*387f9dfdSAndroid Build Coastguard Worker __type(value, struct internal_key);
30*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, MAX_ENTRIES);
31*387f9dfdSAndroid Build Coastguard Worker } start SEC(".maps");
32*387f9dfdSAndroid Build Coastguard Worker
33*387f9dfdSAndroid Build Coastguard Worker struct {
34*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_STACK_TRACE);
35*387f9dfdSAndroid Build Coastguard Worker __uint(key_size, sizeof(u32));
36*387f9dfdSAndroid Build Coastguard Worker } stackmap SEC(".maps");
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker struct {
39*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_HASH);
40*387f9dfdSAndroid Build Coastguard Worker __type(key, struct key_t);
41*387f9dfdSAndroid Build Coastguard Worker __type(value, struct val_t);
42*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, MAX_ENTRIES);
43*387f9dfdSAndroid Build Coastguard Worker } info SEC(".maps");
44*387f9dfdSAndroid Build Coastguard Worker
allow_record(struct task_struct * t)45*387f9dfdSAndroid Build Coastguard Worker static bool allow_record(struct task_struct *t)
46*387f9dfdSAndroid Build Coastguard Worker {
47*387f9dfdSAndroid Build Coastguard Worker if (targ_tgid != -1 && targ_tgid != t->tgid)
48*387f9dfdSAndroid Build Coastguard Worker return false;
49*387f9dfdSAndroid Build Coastguard Worker if (targ_pid != -1 && targ_pid != t->pid)
50*387f9dfdSAndroid Build Coastguard Worker return false;
51*387f9dfdSAndroid Build Coastguard Worker if (user_threads_only && t->flags & PF_KTHREAD)
52*387f9dfdSAndroid Build Coastguard Worker return false;
53*387f9dfdSAndroid Build Coastguard Worker else if (kernel_threads_only && !(t->flags & PF_KTHREAD))
54*387f9dfdSAndroid Build Coastguard Worker return false;
55*387f9dfdSAndroid Build Coastguard Worker if (state != -1 && get_task_state(t) != state)
56*387f9dfdSAndroid Build Coastguard Worker return false;
57*387f9dfdSAndroid Build Coastguard Worker return true;
58*387f9dfdSAndroid Build Coastguard Worker }
59*387f9dfdSAndroid Build Coastguard Worker
60*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/sched_switch")
BPF_PROG(sched_switch,bool preempt,struct task_struct * prev,struct task_struct * next)61*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next)
62*387f9dfdSAndroid Build Coastguard Worker {
63*387f9dfdSAndroid Build Coastguard Worker struct internal_key *i_keyp, i_key;
64*387f9dfdSAndroid Build Coastguard Worker struct val_t *valp, val;
65*387f9dfdSAndroid Build Coastguard Worker s64 delta;
66*387f9dfdSAndroid Build Coastguard Worker u64 udelta;
67*387f9dfdSAndroid Build Coastguard Worker u32 pid;
68*387f9dfdSAndroid Build Coastguard Worker
69*387f9dfdSAndroid Build Coastguard Worker if (allow_record(prev)) {
70*387f9dfdSAndroid Build Coastguard Worker pid = prev->pid;
71*387f9dfdSAndroid Build Coastguard Worker /* To distinguish idle threads of different cores */
72*387f9dfdSAndroid Build Coastguard Worker if (!pid)
73*387f9dfdSAndroid Build Coastguard Worker pid = bpf_get_smp_processor_id();
74*387f9dfdSAndroid Build Coastguard Worker i_key.key.pid = pid;
75*387f9dfdSAndroid Build Coastguard Worker i_key.key.tgid = prev->tgid;
76*387f9dfdSAndroid Build Coastguard Worker i_key.start_ts = bpf_ktime_get_ns();
77*387f9dfdSAndroid Build Coastguard Worker
78*387f9dfdSAndroid Build Coastguard Worker if (prev->flags & PF_KTHREAD)
79*387f9dfdSAndroid Build Coastguard Worker i_key.key.user_stack_id = -1;
80*387f9dfdSAndroid Build Coastguard Worker else
81*387f9dfdSAndroid Build Coastguard Worker i_key.key.user_stack_id =
82*387f9dfdSAndroid Build Coastguard Worker bpf_get_stackid(ctx, &stackmap,
83*387f9dfdSAndroid Build Coastguard Worker BPF_F_USER_STACK);
84*387f9dfdSAndroid Build Coastguard Worker i_key.key.kern_stack_id = bpf_get_stackid(ctx, &stackmap, 0);
85*387f9dfdSAndroid Build Coastguard Worker bpf_map_update_elem(&start, &pid, &i_key, 0);
86*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel_str(&val.comm, sizeof(prev->comm), prev->comm);
87*387f9dfdSAndroid Build Coastguard Worker val.delta = 0;
88*387f9dfdSAndroid Build Coastguard Worker bpf_map_update_elem(&info, &i_key.key, &val, BPF_NOEXIST);
89*387f9dfdSAndroid Build Coastguard Worker }
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Worker pid = next->pid;
92*387f9dfdSAndroid Build Coastguard Worker i_keyp = bpf_map_lookup_elem(&start, &pid);
93*387f9dfdSAndroid Build Coastguard Worker if (!i_keyp)
94*387f9dfdSAndroid Build Coastguard Worker return 0;
95*387f9dfdSAndroid Build Coastguard Worker delta = (s64)(bpf_ktime_get_ns() - i_keyp->start_ts);
96*387f9dfdSAndroid Build Coastguard Worker if (delta < 0)
97*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
98*387f9dfdSAndroid Build Coastguard Worker udelta = (u64)delta;
99*387f9dfdSAndroid Build Coastguard Worker udelta /= 1000U;
100*387f9dfdSAndroid Build Coastguard Worker if (udelta < min_block_ns || udelta > max_block_ns)
101*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
102*387f9dfdSAndroid Build Coastguard Worker valp = bpf_map_lookup_elem(&info, &i_keyp->key);
103*387f9dfdSAndroid Build Coastguard Worker if (!valp)
104*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
105*387f9dfdSAndroid Build Coastguard Worker __sync_fetch_and_add(&valp->delta, udelta);
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker cleanup:
108*387f9dfdSAndroid Build Coastguard Worker bpf_map_delete_elem(&start, &pid);
109*387f9dfdSAndroid Build Coastguard Worker return 0;
110*387f9dfdSAndroid Build Coastguard Worker }
111*387f9dfdSAndroid Build Coastguard Worker
112*387f9dfdSAndroid Build Coastguard Worker char LICENSE[] SEC("license") = "GPL";
113