1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 // Copyright (c) 2021 Google
3 #include "vmlinux.h"
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_tracing.h>
6 
7 // This should be in sync with "util/ftrace.h"
8 #define NUM_BUCKET  22
9 
10 struct {
11 	__uint(type, BPF_MAP_TYPE_HASH);
12 	__uint(key_size, sizeof(__u64));
13 	__uint(value_size, sizeof(__u64));
14 	__uint(max_entries, 10000);
15 } functime SEC(".maps");
16 
17 struct {
18 	__uint(type, BPF_MAP_TYPE_HASH);
19 	__uint(key_size, sizeof(__u32));
20 	__uint(value_size, sizeof(__u8));
21 	__uint(max_entries, 1);
22 } cpu_filter SEC(".maps");
23 
24 struct {
25 	__uint(type, BPF_MAP_TYPE_HASH);
26 	__uint(key_size, sizeof(__u32));
27 	__uint(value_size, sizeof(__u8));
28 	__uint(max_entries, 1);
29 } task_filter SEC(".maps");
30 
31 struct {
32 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
33 	__uint(key_size, sizeof(__u32));
34 	__uint(value_size, sizeof(__u64));
35 	__uint(max_entries, NUM_BUCKET);
36 } latency SEC(".maps");
37 
38 
39 int enabled = 0;
40 int has_cpu = 0;
41 int has_task = 0;
42 
43 SEC("kprobe/func")
44 int BPF_PROG(func_begin)
45 {
46 	__u64 key, now;
47 
48 	if (!enabled)
49 		return 0;
50 
51 	key = bpf_get_current_pid_tgid();
52 
53 	if (has_cpu) {
54 		__u32 cpu = bpf_get_smp_processor_id();
55 		__u8 *ok;
56 
57 		ok = bpf_map_lookup_elem(&cpu_filter, &cpu);
58 		if (!ok)
59 			return 0;
60 	}
61 
62 	if (has_task) {
63 		__u32 pid = key & 0xffffffff;
64 		__u8 *ok;
65 
66 		ok = bpf_map_lookup_elem(&task_filter, &pid);
67 		if (!ok)
68 			return 0;
69 	}
70 
71 	now = bpf_ktime_get_ns();
72 
73 	// overwrite timestamp for nested functions
74 	bpf_map_update_elem(&functime, &key, &now, BPF_ANY);
75 	return 0;
76 }
77 
78 SEC("kretprobe/func")
79 int BPF_PROG(func_end)
80 {
81 	__u64 tid;
82 	__u64 *start;
83 
84 	if (!enabled)
85 		return 0;
86 
87 	tid = bpf_get_current_pid_tgid();
88 
89 	start = bpf_map_lookup_elem(&functime, &tid);
90 	if (start) {
91 		__s64 delta = bpf_ktime_get_ns() - *start;
92 		__u32 key;
93 		__u64 *hist;
94 
95 		bpf_map_delete_elem(&functime, &tid);
96 
97 		if (delta < 0)
98 			return 0;
99 
100 		// calculate index using delta in usec
101 		for (key = 0; key < (NUM_BUCKET - 1); key++) {
102 			if (delta < ((1000UL) << key))
103 				break;
104 		}
105 
106 		hist = bpf_map_lookup_elem(&latency, &key);
107 		if (!hist)
108 			return 0;
109 
110 		*hist += 1;
111 	}
112 
113 	return 0;
114 }
115