112 lines
2.8 KiB
C
112 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (c) 2021 Wenbo Zhang
|
|
#include <vmlinux.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
#include <bpf/bpf_core_read.h>
|
|
#include <bpf/bpf_tracing.h>
|
|
#include "offcputime.h"
|
|
#include "core_fixes.bpf.h"
|
|
|
|
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
|
|
#define MAX_ENTRIES 10240
|
|
|
|
const volatile bool kernel_threads_only = false;
|
|
const volatile bool user_threads_only = false;
|
|
const volatile __u64 max_block_ns = -1;
|
|
const volatile __u64 min_block_ns = 1;
|
|
const volatile pid_t targ_tgid = -1;
|
|
const volatile pid_t targ_pid = -1;
|
|
const volatile long state = -1;
|
|
|
|
struct internal_key {
|
|
u64 start_ts;
|
|
struct key_t key;
|
|
};
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__type(key, u32);
|
|
__type(value, struct internal_key);
|
|
__uint(max_entries, MAX_ENTRIES);
|
|
} start SEC(".maps");
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
|
|
__uint(key_size, sizeof(u32));
|
|
} stackmap SEC(".maps");
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__type(key, struct key_t);
|
|
__type(value, struct val_t);
|
|
__uint(max_entries, MAX_ENTRIES);
|
|
} info SEC(".maps");
|
|
|
|
static bool allow_record(struct task_struct *t)
|
|
{
|
|
if (targ_tgid != -1 && targ_tgid != t->tgid)
|
|
return false;
|
|
if (targ_pid != -1 && targ_pid != t->pid)
|
|
return false;
|
|
if (user_threads_only && t->flags & PF_KTHREAD)
|
|
return false;
|
|
else if (kernel_threads_only && !(t->flags & PF_KTHREAD))
|
|
return false;
|
|
if (state != -1 && get_task_state(t) != state)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
SEC("tp_btf/sched_switch")
|
|
int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev,
|
|
struct task_struct *next)
|
|
{
|
|
struct internal_key *i_keyp, i_key;
|
|
struct val_t *valp, val;
|
|
s64 delta;
|
|
u32 pid;
|
|
|
|
if (allow_record(prev)) {
|
|
pid = prev->pid;
|
|
/* To distinguish idle threads of different cores */
|
|
if (!pid)
|
|
pid = bpf_get_smp_processor_id();
|
|
i_key.key.pid = pid;
|
|
i_key.key.tgid = prev->tgid;
|
|
i_key.start_ts = bpf_ktime_get_ns();
|
|
|
|
if (prev->flags & PF_KTHREAD)
|
|
i_key.key.user_stack_id = -1;
|
|
else
|
|
i_key.key.user_stack_id =
|
|
bpf_get_stackid(ctx, &stackmap,
|
|
BPF_F_USER_STACK);
|
|
i_key.key.kern_stack_id = bpf_get_stackid(ctx, &stackmap, 0);
|
|
bpf_map_update_elem(&start, &pid, &i_key, 0);
|
|
bpf_probe_read_str(&val.comm, sizeof(prev->comm), prev->comm);
|
|
val.delta = 0;
|
|
bpf_map_update_elem(&info, &i_key.key, &val, BPF_NOEXIST);
|
|
}
|
|
|
|
pid = next->pid;
|
|
i_keyp = bpf_map_lookup_elem(&start, &pid);
|
|
if (!i_keyp)
|
|
return 0;
|
|
delta = (s64)(bpf_ktime_get_ns() - i_keyp->start_ts);
|
|
if (delta < 0)
|
|
goto cleanup;
|
|
delta /= 1000U;
|
|
if (delta < min_block_ns || delta > max_block_ns)
|
|
goto cleanup;
|
|
valp = bpf_map_lookup_elem(&info, &i_keyp->key);
|
|
if (!valp)
|
|
goto cleanup;
|
|
__sync_fetch_and_add(&valp->delta, delta);
|
|
|
|
cleanup:
|
|
bpf_map_delete_elem(&start, &pid);
|
|
return 0;
|
|
}
|
|
|
|
char LICENSE[] SEC("license") = "GPL";
|