xref: /aosp_15_r20/external/bcc/libbpf-tools/biostacks.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Wenbo Zhang
3*387f9dfdSAndroid Build Coastguard Worker //
4*387f9dfdSAndroid Build Coastguard Worker // Based on biostacks(8) from BPF-Perf-Tools-Book by Brendan Gregg.
5*387f9dfdSAndroid Build Coastguard Worker // 10-Aug-2020   Wenbo Zhang   Created this.
6*387f9dfdSAndroid Build Coastguard Worker #include <argp.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <signal.h>
8*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
9*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
10*387f9dfdSAndroid Build Coastguard Worker #include <bpf/libbpf.h>
11*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
12*387f9dfdSAndroid Build Coastguard Worker #include "biostacks.h"
13*387f9dfdSAndroid Build Coastguard Worker #include "biostacks.skel.h"
14*387f9dfdSAndroid Build Coastguard Worker #include "trace_helpers.h"
15*387f9dfdSAndroid Build Coastguard Worker 
16*387f9dfdSAndroid Build Coastguard Worker static struct env {
17*387f9dfdSAndroid Build Coastguard Worker 	char *disk;
18*387f9dfdSAndroid Build Coastguard Worker 	int duration;
19*387f9dfdSAndroid Build Coastguard Worker 	bool milliseconds;
20*387f9dfdSAndroid Build Coastguard Worker 	bool verbose;
21*387f9dfdSAndroid Build Coastguard Worker } env = {
22*387f9dfdSAndroid Build Coastguard Worker 	.duration = -1,
23*387f9dfdSAndroid Build Coastguard Worker };
24*387f9dfdSAndroid Build Coastguard Worker 
25*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_version = "biostacks 0.1";
26*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_bug_address =
27*387f9dfdSAndroid Build Coastguard Worker 	"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
28*387f9dfdSAndroid Build Coastguard Worker const char argp_program_doc[] =
29*387f9dfdSAndroid Build Coastguard Worker "Tracing block I/O with init stacks.\n"
30*387f9dfdSAndroid Build Coastguard Worker "\n"
31*387f9dfdSAndroid Build Coastguard Worker "USAGE: biostacks [--help] [-d DISK] [-m] [duration]\n"
32*387f9dfdSAndroid Build Coastguard Worker "\n"
33*387f9dfdSAndroid Build Coastguard Worker "EXAMPLES:\n"
34*387f9dfdSAndroid Build Coastguard Worker "    biostacks              # trace block I/O with init stacks.\n"
35*387f9dfdSAndroid Build Coastguard Worker "    biostacks 1            # trace for 1 seconds only\n"
36*387f9dfdSAndroid Build Coastguard Worker "    biostacks -d sdc       # trace sdc only\n";
37*387f9dfdSAndroid Build Coastguard Worker 
38*387f9dfdSAndroid Build Coastguard Worker static const struct argp_option opts[] = {
39*387f9dfdSAndroid Build Coastguard Worker 	{ "disk",  'd', "DISK",  0, "Trace this disk only" },
40*387f9dfdSAndroid Build Coastguard Worker 	{ "milliseconds", 'm', NULL, 0, "Millisecond histogram" },
41*387f9dfdSAndroid Build Coastguard Worker 	{ "verbose", 'v', NULL, 0, "Verbose debug output" },
42*387f9dfdSAndroid Build Coastguard Worker 	{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
43*387f9dfdSAndroid Build Coastguard Worker 	{},
44*387f9dfdSAndroid Build Coastguard Worker };
45*387f9dfdSAndroid Build Coastguard Worker 
parse_arg(int key,char * arg,struct argp_state * state)46*387f9dfdSAndroid Build Coastguard Worker static error_t parse_arg(int key, char *arg, struct argp_state *state)
47*387f9dfdSAndroid Build Coastguard Worker {
48*387f9dfdSAndroid Build Coastguard Worker 	static int pos_args;
49*387f9dfdSAndroid Build Coastguard Worker 
50*387f9dfdSAndroid Build Coastguard Worker 	switch (key) {
51*387f9dfdSAndroid Build Coastguard Worker 	case 'h':
52*387f9dfdSAndroid Build Coastguard Worker 		argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
53*387f9dfdSAndroid Build Coastguard Worker 		break;
54*387f9dfdSAndroid Build Coastguard Worker 	case 'v':
55*387f9dfdSAndroid Build Coastguard Worker 		env.verbose = true;
56*387f9dfdSAndroid Build Coastguard Worker 		break;
57*387f9dfdSAndroid Build Coastguard Worker 	case 'd':
58*387f9dfdSAndroid Build Coastguard Worker 		env.disk = arg;
59*387f9dfdSAndroid Build Coastguard Worker 		if (strlen(arg) + 1 > DISK_NAME_LEN) {
60*387f9dfdSAndroid Build Coastguard Worker 			fprintf(stderr, "invaild disk name: too long\n");
61*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
62*387f9dfdSAndroid Build Coastguard Worker 		}
63*387f9dfdSAndroid Build Coastguard Worker 		break;
64*387f9dfdSAndroid Build Coastguard Worker 	case 'm':
65*387f9dfdSAndroid Build Coastguard Worker 		env.milliseconds = true;
66*387f9dfdSAndroid Build Coastguard Worker 		break;
67*387f9dfdSAndroid Build Coastguard Worker 	case ARGP_KEY_ARG:
68*387f9dfdSAndroid Build Coastguard Worker 		if (pos_args++) {
69*387f9dfdSAndroid Build Coastguard Worker 			fprintf(stderr,
70*387f9dfdSAndroid Build Coastguard Worker 				"unrecognized positional argument: %s\n", arg);
71*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
72*387f9dfdSAndroid Build Coastguard Worker 		}
73*387f9dfdSAndroid Build Coastguard Worker 		errno = 0;
74*387f9dfdSAndroid Build Coastguard Worker 		env.duration = strtoll(arg, NULL, 10);
75*387f9dfdSAndroid Build Coastguard Worker 		if (errno || env.duration <= 0) {
76*387f9dfdSAndroid Build Coastguard Worker 			fprintf(stderr, "invalid delay (in us): %s\n", arg);
77*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
78*387f9dfdSAndroid Build Coastguard Worker 		}
79*387f9dfdSAndroid Build Coastguard Worker 		break;
80*387f9dfdSAndroid Build Coastguard Worker 	default:
81*387f9dfdSAndroid Build Coastguard Worker 		return ARGP_ERR_UNKNOWN;
82*387f9dfdSAndroid Build Coastguard Worker 	}
83*387f9dfdSAndroid Build Coastguard Worker 	return 0;
84*387f9dfdSAndroid Build Coastguard Worker }
85*387f9dfdSAndroid Build Coastguard Worker 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)86*387f9dfdSAndroid Build Coastguard Worker static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
87*387f9dfdSAndroid Build Coastguard Worker {
88*387f9dfdSAndroid Build Coastguard Worker 	if (level == LIBBPF_DEBUG && !env.verbose)
89*387f9dfdSAndroid Build Coastguard Worker 		return 0;
90*387f9dfdSAndroid Build Coastguard Worker 	return vfprintf(stderr, format, args);
91*387f9dfdSAndroid Build Coastguard Worker }
92*387f9dfdSAndroid Build Coastguard Worker 
sig_handler(int sig)93*387f9dfdSAndroid Build Coastguard Worker static void sig_handler(int sig)
94*387f9dfdSAndroid Build Coastguard Worker {
95*387f9dfdSAndroid Build Coastguard Worker }
96*387f9dfdSAndroid Build Coastguard Worker 
97*387f9dfdSAndroid Build Coastguard Worker static
print_map(struct ksyms * ksyms,struct partitions * partitions,int fd)98*387f9dfdSAndroid Build Coastguard Worker void print_map(struct ksyms *ksyms, struct partitions *partitions, int fd)
99*387f9dfdSAndroid Build Coastguard Worker {
100*387f9dfdSAndroid Build Coastguard Worker 	const char *units = env.milliseconds ? "msecs" : "usecs";
101*387f9dfdSAndroid Build Coastguard Worker 	struct rqinfo lookup_key = {}, next_key;
102*387f9dfdSAndroid Build Coastguard Worker 	const struct partition *partition;
103*387f9dfdSAndroid Build Coastguard Worker 	const struct ksym *ksym;
104*387f9dfdSAndroid Build Coastguard Worker 	int num_stack, i, err;
105*387f9dfdSAndroid Build Coastguard Worker 	struct hist hist;
106*387f9dfdSAndroid Build Coastguard Worker 
107*387f9dfdSAndroid Build Coastguard Worker 	while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) {
108*387f9dfdSAndroid Build Coastguard Worker 		err = bpf_map_lookup_elem(fd, &next_key, &hist);
109*387f9dfdSAndroid Build Coastguard Worker 		if (err < 0) {
110*387f9dfdSAndroid Build Coastguard Worker 			fprintf(stderr, "failed to lookup hist: %d\n", err);
111*387f9dfdSAndroid Build Coastguard Worker 			return;
112*387f9dfdSAndroid Build Coastguard Worker 		}
113*387f9dfdSAndroid Build Coastguard Worker 		partition = partitions__get_by_dev(partitions, next_key.dev);
114*387f9dfdSAndroid Build Coastguard Worker 		printf("%-14.14s %-6d %-7s\n",
115*387f9dfdSAndroid Build Coastguard Worker 			next_key.comm, next_key.pid,
116*387f9dfdSAndroid Build Coastguard Worker 			partition ? partition->name : "Unknown");
117*387f9dfdSAndroid Build Coastguard Worker 		num_stack = next_key.kern_stack_size /
118*387f9dfdSAndroid Build Coastguard Worker 			sizeof(next_key.kern_stack[0]);
119*387f9dfdSAndroid Build Coastguard Worker 		for (i = 0; i < num_stack; i++) {
120*387f9dfdSAndroid Build Coastguard Worker 			ksym = ksyms__map_addr(ksyms, next_key.kern_stack[i]);
121*387f9dfdSAndroid Build Coastguard Worker 			printf("%s\n", ksym ? ksym->name : "Unknown");
122*387f9dfdSAndroid Build Coastguard Worker 		}
123*387f9dfdSAndroid Build Coastguard Worker 		print_log2_hist(hist.slots, MAX_SLOTS, units);
124*387f9dfdSAndroid Build Coastguard Worker 		printf("\n");
125*387f9dfdSAndroid Build Coastguard Worker 		lookup_key = next_key;
126*387f9dfdSAndroid Build Coastguard Worker 	}
127*387f9dfdSAndroid Build Coastguard Worker 
128*387f9dfdSAndroid Build Coastguard Worker 	return;
129*387f9dfdSAndroid Build Coastguard Worker }
130*387f9dfdSAndroid Build Coastguard Worker 
has_block_io_tracepoints(void)131*387f9dfdSAndroid Build Coastguard Worker static bool has_block_io_tracepoints(void)
132*387f9dfdSAndroid Build Coastguard Worker {
133*387f9dfdSAndroid Build Coastguard Worker 	return tracepoint_exists("block", "block_io_start") &&
134*387f9dfdSAndroid Build Coastguard Worker 		tracepoint_exists("block", "block_io_done");
135*387f9dfdSAndroid Build Coastguard Worker }
136*387f9dfdSAndroid Build Coastguard Worker 
disable_block_io_tracepoints(struct biostacks_bpf * obj)137*387f9dfdSAndroid Build Coastguard Worker static void disable_block_io_tracepoints(struct biostacks_bpf *obj)
138*387f9dfdSAndroid Build Coastguard Worker {
139*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.block_io_start, false);
140*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.block_io_done, false);
141*387f9dfdSAndroid Build Coastguard Worker }
142*387f9dfdSAndroid Build Coastguard Worker 
disable_blk_account_io_fentry(struct biostacks_bpf * obj)143*387f9dfdSAndroid Build Coastguard Worker static void disable_blk_account_io_fentry(struct biostacks_bpf *obj)
144*387f9dfdSAndroid Build Coastguard Worker {
145*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.blk_account_io_start, false);
146*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.blk_account_io_done, false);
147*387f9dfdSAndroid Build Coastguard Worker }
148*387f9dfdSAndroid Build Coastguard Worker 
blk_account_io_set_attach_target(struct biostacks_bpf * obj)149*387f9dfdSAndroid Build Coastguard Worker static void blk_account_io_set_attach_target(struct biostacks_bpf *obj)
150*387f9dfdSAndroid Build Coastguard Worker {
151*387f9dfdSAndroid Build Coastguard Worker 	if (fentry_can_attach("blk_account_io_start", NULL)) {
152*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_attach_target(obj->progs.blk_account_io_start,
153*387f9dfdSAndroid Build Coastguard Worker 					       0, "blk_account_io_start");
154*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_attach_target(obj->progs.blk_account_io_done,
155*387f9dfdSAndroid Build Coastguard Worker 					       0, "blk_account_io_done");
156*387f9dfdSAndroid Build Coastguard Worker 	} else {
157*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_attach_target(obj->progs.blk_account_io_start,
158*387f9dfdSAndroid Build Coastguard Worker 					       0, "__blk_account_io_start");
159*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_attach_target(obj->progs.blk_account_io_done,
160*387f9dfdSAndroid Build Coastguard Worker 					       0, "__blk_account_io_done");
161*387f9dfdSAndroid Build Coastguard Worker 	}
162*387f9dfdSAndroid Build Coastguard Worker }
163*387f9dfdSAndroid Build Coastguard Worker 
main(int argc,char ** argv)164*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char **argv)
165*387f9dfdSAndroid Build Coastguard Worker {
166*387f9dfdSAndroid Build Coastguard Worker 	struct partitions *partitions = NULL;
167*387f9dfdSAndroid Build Coastguard Worker 	const struct partition *partition;
168*387f9dfdSAndroid Build Coastguard Worker 	static const struct argp argp = {
169*387f9dfdSAndroid Build Coastguard Worker 		.options = opts,
170*387f9dfdSAndroid Build Coastguard Worker 		.parser = parse_arg,
171*387f9dfdSAndroid Build Coastguard Worker 		.doc = argp_program_doc,
172*387f9dfdSAndroid Build Coastguard Worker 	};
173*387f9dfdSAndroid Build Coastguard Worker 	struct ksyms *ksyms = NULL;
174*387f9dfdSAndroid Build Coastguard Worker 	struct biostacks_bpf *obj;
175*387f9dfdSAndroid Build Coastguard Worker 	int err;
176*387f9dfdSAndroid Build Coastguard Worker 
177*387f9dfdSAndroid Build Coastguard Worker 	err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
178*387f9dfdSAndroid Build Coastguard Worker 	if (err)
179*387f9dfdSAndroid Build Coastguard Worker 		return err;
180*387f9dfdSAndroid Build Coastguard Worker 
181*387f9dfdSAndroid Build Coastguard Worker 	libbpf_set_print(libbpf_print_fn);
182*387f9dfdSAndroid Build Coastguard Worker 
183*387f9dfdSAndroid Build Coastguard Worker 	obj = biostacks_bpf__open();
184*387f9dfdSAndroid Build Coastguard Worker 	if (!obj) {
185*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to open BPF object\n");
186*387f9dfdSAndroid Build Coastguard Worker 		return 1;
187*387f9dfdSAndroid Build Coastguard Worker 	}
188*387f9dfdSAndroid Build Coastguard Worker 
189*387f9dfdSAndroid Build Coastguard Worker 	partitions = partitions__load();
190*387f9dfdSAndroid Build Coastguard Worker 	if (!partitions) {
191*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to load partitions info\n");
192*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
193*387f9dfdSAndroid Build Coastguard Worker 	}
194*387f9dfdSAndroid Build Coastguard Worker 
195*387f9dfdSAndroid Build Coastguard Worker 	/* initialize global data (filtering options) */
196*387f9dfdSAndroid Build Coastguard Worker 	if (env.disk) {
197*387f9dfdSAndroid Build Coastguard Worker 		partition = partitions__get_by_name(partitions, env.disk);
198*387f9dfdSAndroid Build Coastguard Worker 		if (!partition) {
199*387f9dfdSAndroid Build Coastguard Worker 			fprintf(stderr, "invaild partition name: not exist\n");
200*387f9dfdSAndroid Build Coastguard Worker 			goto cleanup;
201*387f9dfdSAndroid Build Coastguard Worker 		}
202*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->filter_dev = true;
203*387f9dfdSAndroid Build Coastguard Worker 		obj->rodata->targ_dev = partition->dev;
204*387f9dfdSAndroid Build Coastguard Worker 	}
205*387f9dfdSAndroid Build Coastguard Worker 
206*387f9dfdSAndroid Build Coastguard Worker 	obj->rodata->targ_ms = env.milliseconds;
207*387f9dfdSAndroid Build Coastguard Worker 
208*387f9dfdSAndroid Build Coastguard Worker 	if (has_block_io_tracepoints())
209*387f9dfdSAndroid Build Coastguard Worker 		disable_blk_account_io_fentry(obj);
210*387f9dfdSAndroid Build Coastguard Worker 	else {
211*387f9dfdSAndroid Build Coastguard Worker 		disable_block_io_tracepoints(obj);
212*387f9dfdSAndroid Build Coastguard Worker 		blk_account_io_set_attach_target(obj);
213*387f9dfdSAndroid Build Coastguard Worker 	}
214*387f9dfdSAndroid Build Coastguard Worker 
215*387f9dfdSAndroid Build Coastguard Worker 	ksyms = ksyms__load();
216*387f9dfdSAndroid Build Coastguard Worker 	if (!ksyms) {
217*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to load kallsyms\n");
218*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
219*387f9dfdSAndroid Build Coastguard Worker 	}
220*387f9dfdSAndroid Build Coastguard Worker 	if (!ksyms__get_symbol(ksyms, "blk_account_io_merge_bio"))
221*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(obj->progs.blk_account_io_merge_bio, false);
222*387f9dfdSAndroid Build Coastguard Worker 
223*387f9dfdSAndroid Build Coastguard Worker 	err = biostacks_bpf__load(obj);
224*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
225*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to load BPF object: %d\n", err);
226*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
227*387f9dfdSAndroid Build Coastguard Worker 	}
228*387f9dfdSAndroid Build Coastguard Worker 
229*387f9dfdSAndroid Build Coastguard Worker 	err = biostacks_bpf__attach(obj);
230*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
231*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to attach BPF programs: %d\n", err);
232*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
233*387f9dfdSAndroid Build Coastguard Worker 	}
234*387f9dfdSAndroid Build Coastguard Worker 
235*387f9dfdSAndroid Build Coastguard Worker 	signal(SIGINT, sig_handler);
236*387f9dfdSAndroid Build Coastguard Worker 
237*387f9dfdSAndroid Build Coastguard Worker 	printf("Tracing block I/O with init stacks. Hit Ctrl-C to end.\n");
238*387f9dfdSAndroid Build Coastguard Worker 	sleep(env.duration);
239*387f9dfdSAndroid Build Coastguard Worker 	print_map(ksyms, partitions, bpf_map__fd(obj->maps.hists));
240*387f9dfdSAndroid Build Coastguard Worker 
241*387f9dfdSAndroid Build Coastguard Worker cleanup:
242*387f9dfdSAndroid Build Coastguard Worker 	biostacks_bpf__destroy(obj);
243*387f9dfdSAndroid Build Coastguard Worker 	ksyms__free(ksyms);
244*387f9dfdSAndroid Build Coastguard Worker 	partitions__free(partitions);
245*387f9dfdSAndroid Build Coastguard Worker 
246*387f9dfdSAndroid Build Coastguard Worker 	return err != 0;
247*387f9dfdSAndroid Build Coastguard Worker }
248