Blame view

samples/bpf/sampleip_user.c 4.83 KB
25763b3c8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
72874418e   Brendan Gregg   samples/bpf: add ...
2
3
4
5
  /*
   * sampleip: sample instruction pointer and frequency count in a BPF map.
   *
   * Copyright 2016 Netflix, Inc.
72874418e   Brendan Gregg   samples/bpf: add ...
6
7
8
   */
  #include <stdio.h>
  #include <stdlib.h>
72874418e   Brendan Gregg   samples/bpf: add ...
9
10
11
12
  #include <unistd.h>
  #include <errno.h>
  #include <signal.h>
  #include <string.h>
72874418e   Brendan Gregg   samples/bpf: add ...
13
14
15
  #include <linux/perf_event.h>
  #include <linux/ptrace.h>
  #include <linux/bpf.h>
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
16
  #include <bpf/bpf.h>
7cf245a37   Toke Høiland-Jørgensen   samples/bpf: Use ...
17
  #include <bpf/libbpf.h>
205c8ada3   Joe Stringer   samples/bpf: Remo...
18
  #include "perf-sys.h"
28dbf861d   Yonghong Song   samples/bpf: move...
19
  #include "trace_helpers.h"
72874418e   Brendan Gregg   samples/bpf: add ...
20
21
22
23
24
  
  #define DEFAULT_FREQ	99
  #define DEFAULT_SECS	5
  #define MAX_IPS		8192
  #define PAGE_OFFSET	0xffff880000000000
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
25
  static int map_fd;
72874418e   Brendan Gregg   samples/bpf: add ...
26
27
28
29
30
31
32
33
34
35
36
  static int nr_cpus;
  
  static void usage(void)
  {
  	printf("USAGE: sampleip [-F freq] [duration]
  ");
  	printf("       -F freq    # sample frequency (Hertz), default 99
  ");
  	printf("       duration   # sampling duration (seconds), default 5
  ");
  }
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
37
38
  static int sampling_start(int freq, struct bpf_program *prog,
  			  struct bpf_link *links[])
72874418e   Brendan Gregg   samples/bpf: add ...
39
  {
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
40
  	int i, pmu_fd;
72874418e   Brendan Gregg   samples/bpf: add ...
41
42
43
44
45
46
47
48
49
50
  
  	struct perf_event_attr pe_sample_attr = {
  		.type = PERF_TYPE_SOFTWARE,
  		.freq = 1,
  		.sample_period = freq,
  		.config = PERF_COUNT_SW_CPU_CLOCK,
  		.inherit = 1,
  	};
  
  	for (i = 0; i < nr_cpus; i++) {
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
51
  		pmu_fd = sys_perf_event_open(&pe_sample_attr, -1 /* pid */, i,
72874418e   Brendan Gregg   samples/bpf: add ...
52
  					    -1 /* group_fd */, 0 /* flags */);
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
53
  		if (pmu_fd < 0) {
72874418e   Brendan Gregg   samples/bpf: add ...
54
55
56
57
  			fprintf(stderr, "ERROR: Initializing perf sampling
  ");
  			return 1;
  		}
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
58
  		links[i] = bpf_program__attach_perf_event(prog, pmu_fd);
0efdcefb0   Daniel T. Lee   samples, bpf: Ref...
59
  		if (libbpf_get_error(links[i])) {
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
60
61
62
63
64
65
  			fprintf(stderr, "ERROR: Attach perf event
  ");
  			links[i] = NULL;
  			close(pmu_fd);
  			return 1;
  		}
72874418e   Brendan Gregg   samples/bpf: add ...
66
67
68
69
  	}
  
  	return 0;
  }
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
70
  static void sampling_end(struct bpf_link *links[])
72874418e   Brendan Gregg   samples/bpf: add ...
71
72
73
74
  {
  	int i;
  
  	for (i = 0; i < nr_cpus; i++)
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
75
  		bpf_link__destroy(links[i]);
72874418e   Brendan Gregg   samples/bpf: add ...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  }
  
  struct ipcount {
  	__u64 ip;
  	__u32 count;
  };
  
  /* used for sorting */
  struct ipcount counts[MAX_IPS];
  
  static int count_cmp(const void *p1, const void *p2)
  {
  	return ((struct ipcount *)p1)->count - ((struct ipcount *)p2)->count;
  }
  
  static void print_ip_map(int fd)
  {
  	struct ksym *sym;
  	__u64 key, next_key;
  	__u32 value;
  	int i, max;
  
  	printf("%-19s %-32s %s
  ", "ADDR", "KSYM", "COUNT");
  
  	/* fetch IPs and counts */
  	key = 0, i = 0;
d40fc181e   Joe Stringer   samples/bpf: Make...
103
104
  	while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
  		bpf_map_lookup_elem(fd, &next_key, &value);
72874418e   Brendan Gregg   samples/bpf: add ...
105
106
107
108
109
110
111
112
113
114
115
  		counts[i].ip = next_key;
  		counts[i++].count = value;
  		key = next_key;
  	}
  	max = i;
  
  	/* sort and print */
  	qsort(counts, max, sizeof(struct ipcount), count_cmp);
  	for (i = 0; i < max; i++) {
  		if (counts[i].ip > PAGE_OFFSET) {
  			sym = ksym_search(counts[i].ip);
e67b2c715   Daniel T. Lee   samples, selftest...
116
117
118
119
120
  			if (!sym) {
  				printf("ksym not found. Is kallsyms loaded?
  ");
  				continue;
  			}
72874418e   Brendan Gregg   samples/bpf: add ...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  			printf("0x%-17llx %-32s %u
  ", counts[i].ip, sym->name,
  			       counts[i].count);
  		} else {
  			printf("0x%-17llx %-32s %u
  ", counts[i].ip, "(user)",
  			       counts[i].count);
  		}
  	}
  
  	if (max == MAX_IPS) {
  		printf("WARNING: IP hash was full (max %d entries); ", max);
  		printf("may have dropped samples
  ");
  	}
  }
  
  static void int_exit(int sig)
  {
  	printf("
  ");
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
142
  	print_ip_map(map_fd);
72874418e   Brendan Gregg   samples/bpf: add ...
143
144
145
146
147
  	exit(0);
  }
  
  int main(int argc, char **argv)
  {
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
148
149
150
151
  	int opt, freq = DEFAULT_FREQ, secs = DEFAULT_SECS, error = 1;
  	struct bpf_object *obj = NULL;
  	struct bpf_program *prog;
  	struct bpf_link **links;
72874418e   Brendan Gregg   samples/bpf: add ...
152
  	char filename[256];
72874418e   Brendan Gregg   samples/bpf: add ...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  
  	/* process arguments */
  	while ((opt = getopt(argc, argv, "F:h")) != -1) {
  		switch (opt) {
  		case 'F':
  			freq = atoi(optarg);
  			break;
  		case 'h':
  		default:
  			usage();
  			return 0;
  		}
  	}
  	if (argc - optind == 1)
  		secs = atoi(argv[optind]);
  	if (freq == 0 || secs == 0) {
  		usage();
  		return 1;
  	}
  
  	/* initialize kernel symbol translation */
  	if (load_kallsyms()) {
  		fprintf(stderr, "ERROR: loading /proc/kallsyms
  ");
  		return 2;
  	}
  
  	/* create perf FDs for each CPU */
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
181
182
183
184
185
186
  	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  	links = calloc(nr_cpus, sizeof(struct bpf_link *));
  	if (!links) {
  		fprintf(stderr, "ERROR: malloc of links
  ");
  		goto cleanup;
72874418e   Brendan Gregg   samples/bpf: add ...
187
  	}
72874418e   Brendan Gregg   samples/bpf: add ...
188
  	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
189
  	obj = bpf_object__open_file(filename, NULL);
0efdcefb0   Daniel T. Lee   samples, bpf: Ref...
190
  	if (libbpf_get_error(obj)) {
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
191
192
193
194
195
196
197
198
199
200
201
  		fprintf(stderr, "ERROR: opening BPF object file failed
  ");
  		obj = NULL;
  		goto cleanup;
  	}
  
  	prog = bpf_object__find_program_by_name(obj, "do_sample");
  	if (!prog) {
  		fprintf(stderr, "ERROR: finding a prog in obj file failed
  ");
  		goto cleanup;
72874418e   Brendan Gregg   samples/bpf: add ...
202
  	}
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  
  	/* load BPF program */
  	if (bpf_object__load(obj)) {
  		fprintf(stderr, "ERROR: loading BPF object file failed
  ");
  		goto cleanup;
  	}
  
  	map_fd = bpf_object__find_map_fd_by_name(obj, "ip_map");
  	if (map_fd < 0) {
  		fprintf(stderr, "ERROR: finding a map in obj file failed
  ");
  		goto cleanup;
  	}
72874418e   Brendan Gregg   samples/bpf: add ...
217
  	signal(SIGINT, int_exit);
ad990dbe6   Andy Gospodarek   samples/bpf: run ...
218
  	signal(SIGTERM, int_exit);
72874418e   Brendan Gregg   samples/bpf: add ...
219
220
221
222
223
  
  	/* do sampling */
  	printf("Sampling at %d Hertz for %d seconds. Ctrl-C also ends.
  ",
  	       freq, secs);
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
224
225
  	if (sampling_start(freq, prog, links) != 0)
  		goto cleanup;
72874418e   Brendan Gregg   samples/bpf: add ...
226
  	sleep(secs);
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
227
  	error = 0;
72874418e   Brendan Gregg   samples/bpf: add ...
228

aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
229
230
  cleanup:
  	sampling_end(links);
72874418e   Brendan Gregg   samples/bpf: add ...
231
  	/* output sample counts */
aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
232
233
  	if (!error)
  		print_ip_map(map_fd);
72874418e   Brendan Gregg   samples/bpf: add ...
234

aa5e2af66   Daniel T. Lee   samples, bpf: Ref...
235
236
237
  	free(links);
  	bpf_object__close(obj);
  	return error;
72874418e   Brendan Gregg   samples/bpf: add ...
238
  }