forked from grafana/opentelemetry-ebpf-profiler
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoff_cpu.ebpf.c
More file actions
89 lines (72 loc) · 2.48 KB
/
Copy pathoff_cpu.ebpf.c
File metadata and controls
89 lines (72 loc) · 2.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "bpfdefs.h"
#include "tracemgmt.h"
#include "types.h"
// kprobe_progs maps from a program ID to a kprobe eBPF program
struct kprobe_progs_t {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__type(key, u32);
__type(value, u32);
__uint(max_entries, NUM_TRACER_PROGS);
} kprobe_progs SEC(".maps");
// sched_times keeps track of sched_switch call times.
struct sched_times_t {
__uint(type, BPF_MAP_TYPE_LRU_PERCPU_HASH);
__type(key, u64); // pid_tgid
__type(value, u64); // time in ns
__uint(max_entries, 256); // value is adjusted at load time in loadAllMaps.
} sched_times SEC(".maps");
// off_cpu_threshold is set during load time.
BPF_RODATA_VAR(u32, off_cpu_threshold, 0)
// tracepoint__sched_switch serves as entry point for off cpu profiling.
SEC("tracepoint/sched/sched_switch")
int tracepoint__sched_switch(UNUSED void *ctx)
{
u64 pid_tgid = bpf_get_current_pid_tgid();
u32 pid = pid_tgid >> 32;
u32 tid = pid_tgid & 0xFFFFFFFF;
if (pid == 0 || tid == 0) {
return 0;
}
if (bpf_get_prandom_u32() > off_cpu_threshold) {
return 0;
}
u64 ts = bpf_ktime_get_ns();
if (bpf_map_update_elem(&sched_times, &pid_tgid, &ts, BPF_ANY) < 0) {
DEBUG_PRINT("Failed to record sched_switch event entry");
return 0;
}
return 0;
}
// kprobe__dummy is never loaded or called. It just makes sure kprobe_progs is
// referenced and make the compiler and linker happy.
SEC("kprobe/dummy")
int kprobe__dummy(struct pt_regs *ctx)
{
bpf_tail_call(ctx, &kprobe_progs, 0);
return 0;
}
// kp__finish_task_switch is triggered right after the scheduler updated
// the CPU registers.
SEC("kprobe/finish_task_switch")
int finish_task_switch(struct pt_regs *ctx)
{
// Get the PID and TGID register.
u64 pid_tgid = bpf_get_current_pid_tgid();
u32 pid = pid_tgid >> 32;
u32 tid = pid_tgid & 0xFFFFFFFF;
if (pid == 0 || tid == 0) {
return 0;
}
u64 ts = bpf_ktime_get_ns();
u64 *start_ts = bpf_map_lookup_elem(&sched_times, &pid_tgid);
if (!start_ts || *start_ts == 0) {
// There is no information from the sched/sched_switch entry hook.
return 0;
}
// Remove entry from the map so the stack for the same pid_tgid does not get unwound and
// reported accidentally without the start timestamp updated in tracepoint/sched/sched_switch.
bpf_map_delete_elem(&sched_times, &pid_tgid);
u64 diff = ts - *start_ts;
DEBUG_PRINT("==== finish_task_switch ====");
return collect_trace(ctx, TRACE_OFF_CPU, pid, tid, ts, diff);
}