Merge branch 'parisc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[cascardo/linux.git] / samples / bpf / trace_event_user.c
1 /* Copyright (c) 2016 Facebook
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of version 2 of the GNU General Public
5  * License as published by the Free Software Foundation.
6  */
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <poll.h>
14 #include <sys/ioctl.h>
15 #include <linux/perf_event.h>
16 #include <linux/bpf.h>
17 #include <signal.h>
18 #include <assert.h>
19 #include <errno.h>
20 #include <sys/resource.h>
21 #include "libbpf.h"
22 #include "bpf_load.h"
23
24 #define SAMPLE_FREQ 50
25
26 static bool sys_read_seen, sys_write_seen;
27
28 static void print_ksym(__u64 addr)
29 {
30         struct ksym *sym;
31
32         if (!addr)
33                 return;
34         sym = ksym_search(addr);
35         printf("%s;", sym->name);
36         if (!strcmp(sym->name, "sys_read"))
37                 sys_read_seen = true;
38         else if (!strcmp(sym->name, "sys_write"))
39                 sys_write_seen = true;
40 }
41
42 static void print_addr(__u64 addr)
43 {
44         if (!addr)
45                 return;
46         printf("%llx;", addr);
47 }
48
49 #define TASK_COMM_LEN 16
50
51 struct key_t {
52         char comm[TASK_COMM_LEN];
53         __u32 kernstack;
54         __u32 userstack;
55 };
56
57 static void print_stack(struct key_t *key, __u64 count)
58 {
59         __u64 ip[PERF_MAX_STACK_DEPTH] = {};
60         static bool warned;
61         int i;
62
63         printf("%3lld %s;", count, key->comm);
64         if (bpf_lookup_elem(map_fd[1], &key->kernstack, ip) != 0) {
65                 printf("---;");
66         } else {
67                 for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--)
68                         print_ksym(ip[i]);
69         }
70         printf("-;");
71         if (bpf_lookup_elem(map_fd[1], &key->userstack, ip) != 0) {
72                 printf("---;");
73         } else {
74                 for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--)
75                         print_addr(ip[i]);
76         }
77         printf("\n");
78
79         if (key->kernstack == -EEXIST && !warned) {
80                 printf("stackmap collisions seen. Consider increasing size\n");
81                 warned = true;
82         } else if ((int)key->kernstack < 0 && (int)key->userstack < 0) {
83                 printf("err stackid %d %d\n", key->kernstack, key->userstack);
84         }
85 }
86
87 static void int_exit(int sig)
88 {
89         kill(0, SIGKILL);
90         exit(0);
91 }
92
93 static void print_stacks(void)
94 {
95         struct key_t key = {}, next_key;
96         __u64 value;
97         __u32 stackid = 0, next_id;
98         int fd = map_fd[0], stack_map = map_fd[1];
99
100         sys_read_seen = sys_write_seen = false;
101         while (bpf_get_next_key(fd, &key, &next_key) == 0) {
102                 bpf_lookup_elem(fd, &next_key, &value);
103                 print_stack(&next_key, value);
104                 bpf_delete_elem(fd, &next_key);
105                 key = next_key;
106         }
107
108         if (!sys_read_seen || !sys_write_seen) {
109                 printf("BUG kernel stack doesn't contain sys_read() and sys_write()\n");
110                 int_exit(0);
111         }
112
113         /* clear stack map */
114         while (bpf_get_next_key(stack_map, &stackid, &next_id) == 0) {
115                 bpf_delete_elem(stack_map, &next_id);
116                 stackid = next_id;
117         }
118 }
119
120 static void test_perf_event_all_cpu(struct perf_event_attr *attr)
121 {
122         int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
123         int *pmu_fd = malloc(nr_cpus * sizeof(int));
124         int i;
125
126         /* open perf_event on all cpus */
127         for (i = 0; i < nr_cpus; i++) {
128                 pmu_fd[i] = perf_event_open(attr, -1, i, -1, 0);
129                 if (pmu_fd[i] < 0) {
130                         printf("perf_event_open failed\n");
131                         goto all_cpu_err;
132                 }
133                 assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_SET_BPF, prog_fd[0]) == 0);
134                 assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_ENABLE, 0) == 0);
135         }
136         system("dd if=/dev/zero of=/dev/null count=5000k");
137         print_stacks();
138 all_cpu_err:
139         for (i--; i >= 0; i--)
140                 close(pmu_fd[i]);
141         free(pmu_fd);
142 }
143
144 static void test_perf_event_task(struct perf_event_attr *attr)
145 {
146         int pmu_fd;
147
148         /* open task bound event */
149         pmu_fd = perf_event_open(attr, 0, -1, -1, 0);
150         if (pmu_fd < 0) {
151                 printf("perf_event_open failed\n");
152                 return;
153         }
154         assert(ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd[0]) == 0);
155         assert(ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0) == 0);
156         system("dd if=/dev/zero of=/dev/null count=5000k");
157         print_stacks();
158         close(pmu_fd);
159 }
160
161 static void test_bpf_perf_event(void)
162 {
163         struct perf_event_attr attr_type_hw = {
164                 .sample_freq = SAMPLE_FREQ,
165                 .freq = 1,
166                 .type = PERF_TYPE_HARDWARE,
167                 .config = PERF_COUNT_HW_CPU_CYCLES,
168                 .inherit = 1,
169         };
170         struct perf_event_attr attr_type_sw = {
171                 .sample_freq = SAMPLE_FREQ,
172                 .freq = 1,
173                 .type = PERF_TYPE_SOFTWARE,
174                 .config = PERF_COUNT_SW_CPU_CLOCK,
175                 .inherit = 1,
176         };
177
178         test_perf_event_all_cpu(&attr_type_hw);
179         test_perf_event_task(&attr_type_hw);
180         test_perf_event_all_cpu(&attr_type_sw);
181         test_perf_event_task(&attr_type_sw);
182 }
183
184
185 int main(int argc, char **argv)
186 {
187         struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
188         char filename[256];
189
190         snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
191         setrlimit(RLIMIT_MEMLOCK, &r);
192
193         signal(SIGINT, int_exit);
194
195         if (load_kallsyms()) {
196                 printf("failed to process /proc/kallsyms\n");
197                 return 1;
198         }
199
200         if (load_bpf_file(filename)) {
201                 printf("%s", bpf_log_buf);
202                 return 2;
203         }
204
205         if (fork() == 0) {
206                 read_trace_pipe();
207                 return 0;
208         }
209         test_bpf_perf_event();
210
211         int_exit(0);
212         return 0;
213 }