Merge branch 'for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[sfrench/cifs-2.6.git] / tools / perf / util / bpf_skel / func_latency.bpf.c
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 }