xref: /aosp_15_r20/external/bcc/libbpf-tools/vfsstat.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Anton Protopopov
3*387f9dfdSAndroid Build Coastguard Worker //
4*387f9dfdSAndroid Build Coastguard Worker // Based on vfsstat(8) from BCC by Brendan Gregg
5*387f9dfdSAndroid Build Coastguard Worker #include <argp.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <time.h>
8*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
9*387f9dfdSAndroid Build Coastguard Worker #include "vfsstat.h"
10*387f9dfdSAndroid Build Coastguard Worker #include "vfsstat.skel.h"
11*387f9dfdSAndroid Build Coastguard Worker #include "btf_helpers.h"
12*387f9dfdSAndroid Build Coastguard Worker #include "trace_helpers.h"
13*387f9dfdSAndroid Build Coastguard Worker 
14*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_version = "vfsstat 0.1";
15*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_bug_address =
16*387f9dfdSAndroid Build Coastguard Worker 	"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
17*387f9dfdSAndroid Build Coastguard Worker static const char argp_program_doc[] =
18*387f9dfdSAndroid Build Coastguard Worker 	"\nvfsstat: Count some VFS calls\n"
19*387f9dfdSAndroid Build Coastguard Worker 	"\n"
20*387f9dfdSAndroid Build Coastguard Worker 	"EXAMPLES:\n"
21*387f9dfdSAndroid Build Coastguard Worker 	"    vfsstat      # interval one second\n"
22*387f9dfdSAndroid Build Coastguard Worker 	"    vfsstat 5 3  # interval five seconds, three output lines\n";
23*387f9dfdSAndroid Build Coastguard Worker static char args_doc[] = "[interval [count]]";
24*387f9dfdSAndroid Build Coastguard Worker 
25*387f9dfdSAndroid Build Coastguard Worker static const struct argp_option opts[] = {
26*387f9dfdSAndroid Build Coastguard Worker 	{ "verbose", 'v', NULL, 0, "Verbose debug output" },
27*387f9dfdSAndroid Build Coastguard Worker 	{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
28*387f9dfdSAndroid Build Coastguard Worker 	{},
29*387f9dfdSAndroid Build Coastguard Worker };
30*387f9dfdSAndroid Build Coastguard Worker 
31*387f9dfdSAndroid Build Coastguard Worker static struct env {
32*387f9dfdSAndroid Build Coastguard Worker 	bool verbose;
33*387f9dfdSAndroid Build Coastguard Worker 	int count;
34*387f9dfdSAndroid Build Coastguard Worker 	int interval;
35*387f9dfdSAndroid Build Coastguard Worker } env = {
36*387f9dfdSAndroid Build Coastguard Worker 	.interval = 1,	/* once a second */
37*387f9dfdSAndroid Build Coastguard Worker };
38*387f9dfdSAndroid Build Coastguard Worker 
parse_arg(int key,char * arg,struct argp_state * state)39*387f9dfdSAndroid Build Coastguard Worker static error_t parse_arg(int key, char *arg, struct argp_state *state)
40*387f9dfdSAndroid Build Coastguard Worker {
41*387f9dfdSAndroid Build Coastguard Worker 	long interval;
42*387f9dfdSAndroid Build Coastguard Worker 	long count;
43*387f9dfdSAndroid Build Coastguard Worker 
44*387f9dfdSAndroid Build Coastguard Worker 	switch (key) {
45*387f9dfdSAndroid Build Coastguard Worker 	case 'h':
46*387f9dfdSAndroid Build Coastguard Worker 		argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
47*387f9dfdSAndroid Build Coastguard Worker 		break;
48*387f9dfdSAndroid Build Coastguard Worker 	case 'v':
49*387f9dfdSAndroid Build Coastguard Worker 		env.verbose = true;
50*387f9dfdSAndroid Build Coastguard Worker 		break;
51*387f9dfdSAndroid Build Coastguard Worker 	case ARGP_KEY_ARG:
52*387f9dfdSAndroid Build Coastguard Worker 		switch (state->arg_num) {
53*387f9dfdSAndroid Build Coastguard Worker 		case 0:
54*387f9dfdSAndroid Build Coastguard Worker 			errno = 0;
55*387f9dfdSAndroid Build Coastguard Worker 			interval = strtol(arg, NULL, 10);
56*387f9dfdSAndroid Build Coastguard Worker 			if (errno || interval <= 0 || interval > INT_MAX) {
57*387f9dfdSAndroid Build Coastguard Worker 				fprintf(stderr, "invalid interval: %s\n", arg);
58*387f9dfdSAndroid Build Coastguard Worker 				argp_usage(state);
59*387f9dfdSAndroid Build Coastguard Worker 			}
60*387f9dfdSAndroid Build Coastguard Worker 			env.interval = interval;
61*387f9dfdSAndroid Build Coastguard Worker 			break;
62*387f9dfdSAndroid Build Coastguard Worker 		case 1:
63*387f9dfdSAndroid Build Coastguard Worker 			errno = 0;
64*387f9dfdSAndroid Build Coastguard Worker 			count = strtol(arg, NULL, 10);
65*387f9dfdSAndroid Build Coastguard Worker 			if (errno || count < 0 || count > INT_MAX) {
66*387f9dfdSAndroid Build Coastguard Worker 				fprintf(stderr, "invalid count: %s\n", arg);
67*387f9dfdSAndroid Build Coastguard Worker 				argp_usage(state);
68*387f9dfdSAndroid Build Coastguard Worker 			}
69*387f9dfdSAndroid Build Coastguard Worker 			env.count = count;
70*387f9dfdSAndroid Build Coastguard Worker 			break;
71*387f9dfdSAndroid Build Coastguard Worker 		default:
72*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
73*387f9dfdSAndroid Build Coastguard Worker 			break;
74*387f9dfdSAndroid Build Coastguard Worker 		}
75*387f9dfdSAndroid Build Coastguard Worker 		break;
76*387f9dfdSAndroid Build Coastguard Worker 	default:
77*387f9dfdSAndroid Build Coastguard Worker 		return ARGP_ERR_UNKNOWN;
78*387f9dfdSAndroid Build Coastguard Worker 	}
79*387f9dfdSAndroid Build Coastguard Worker 	return 0;
80*387f9dfdSAndroid Build Coastguard Worker }
81*387f9dfdSAndroid Build Coastguard Worker 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)82*387f9dfdSAndroid Build Coastguard Worker static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
83*387f9dfdSAndroid Build Coastguard Worker {
84*387f9dfdSAndroid Build Coastguard Worker 	if (level == LIBBPF_DEBUG && !env.verbose)
85*387f9dfdSAndroid Build Coastguard Worker 		return 0;
86*387f9dfdSAndroid Build Coastguard Worker 	return vfprintf(stderr, format, args);
87*387f9dfdSAndroid Build Coastguard Worker }
88*387f9dfdSAndroid Build Coastguard Worker 
strftime_now(char * s,size_t max,const char * format)89*387f9dfdSAndroid Build Coastguard Worker static const char *strftime_now(char *s, size_t max, const char *format)
90*387f9dfdSAndroid Build Coastguard Worker {
91*387f9dfdSAndroid Build Coastguard Worker 	struct tm *tm;
92*387f9dfdSAndroid Build Coastguard Worker 	time_t t;
93*387f9dfdSAndroid Build Coastguard Worker 
94*387f9dfdSAndroid Build Coastguard Worker 	t = time(NULL);
95*387f9dfdSAndroid Build Coastguard Worker 	tm = localtime(&t);
96*387f9dfdSAndroid Build Coastguard Worker 	if (tm == NULL) {
97*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "localtime: %s\n", strerror(errno));
98*387f9dfdSAndroid Build Coastguard Worker 		return "<failed>";
99*387f9dfdSAndroid Build Coastguard Worker 	}
100*387f9dfdSAndroid Build Coastguard Worker 	if (strftime(s, max, format, tm) == 0) {
101*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "strftime error\n");
102*387f9dfdSAndroid Build Coastguard Worker 		return "<failed>";
103*387f9dfdSAndroid Build Coastguard Worker 	}
104*387f9dfdSAndroid Build Coastguard Worker 	return s;
105*387f9dfdSAndroid Build Coastguard Worker }
106*387f9dfdSAndroid Build Coastguard Worker 
107*387f9dfdSAndroid Build Coastguard Worker static const char *stat_types_names[] = {
108*387f9dfdSAndroid Build Coastguard Worker 	[S_READ] = "READ",
109*387f9dfdSAndroid Build Coastguard Worker 	[S_WRITE] = "WRITE",
110*387f9dfdSAndroid Build Coastguard Worker 	[S_FSYNC] = "FSYNC",
111*387f9dfdSAndroid Build Coastguard Worker 	[S_OPEN] = "OPEN",
112*387f9dfdSAndroid Build Coastguard Worker 	[S_CREATE] = "CREATE",
113*387f9dfdSAndroid Build Coastguard Worker };
114*387f9dfdSAndroid Build Coastguard Worker 
print_header(void)115*387f9dfdSAndroid Build Coastguard Worker static void print_header(void)
116*387f9dfdSAndroid Build Coastguard Worker {
117*387f9dfdSAndroid Build Coastguard Worker 	int i;
118*387f9dfdSAndroid Build Coastguard Worker 
119*387f9dfdSAndroid Build Coastguard Worker 	printf("%-8s  ", "TIME");
120*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < S_MAXSTAT; i++)
121*387f9dfdSAndroid Build Coastguard Worker 		printf(" %6s/s", stat_types_names[i]);
122*387f9dfdSAndroid Build Coastguard Worker 	printf("\n");
123*387f9dfdSAndroid Build Coastguard Worker }
124*387f9dfdSAndroid Build Coastguard Worker 
print_and_reset_stats(__u64 stats[S_MAXSTAT])125*387f9dfdSAndroid Build Coastguard Worker static void print_and_reset_stats(__u64 stats[S_MAXSTAT])
126*387f9dfdSAndroid Build Coastguard Worker {
127*387f9dfdSAndroid Build Coastguard Worker 	char s[16];
128*387f9dfdSAndroid Build Coastguard Worker 	__u64 val;
129*387f9dfdSAndroid Build Coastguard Worker 	int i;
130*387f9dfdSAndroid Build Coastguard Worker 
131*387f9dfdSAndroid Build Coastguard Worker 	printf("%-8s: ", strftime_now(s, sizeof(s), "%H:%M:%S"));
132*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < S_MAXSTAT; i++) {
133*387f9dfdSAndroid Build Coastguard Worker 		val = __atomic_exchange_n(&stats[i], 0, __ATOMIC_RELAXED);
134*387f9dfdSAndroid Build Coastguard Worker 		printf(" %8llu", val / env.interval);
135*387f9dfdSAndroid Build Coastguard Worker 	}
136*387f9dfdSAndroid Build Coastguard Worker 	printf("\n");
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker 
main(int argc,char ** argv)139*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char **argv)
140*387f9dfdSAndroid Build Coastguard Worker {
141*387f9dfdSAndroid Build Coastguard Worker 	LIBBPF_OPTS(bpf_object_open_opts, open_opts);
142*387f9dfdSAndroid Build Coastguard Worker 	static const struct argp argp = {
143*387f9dfdSAndroid Build Coastguard Worker 		.options = opts,
144*387f9dfdSAndroid Build Coastguard Worker 		.parser = parse_arg,
145*387f9dfdSAndroid Build Coastguard Worker 		.doc = argp_program_doc,
146*387f9dfdSAndroid Build Coastguard Worker 		.args_doc = args_doc,
147*387f9dfdSAndroid Build Coastguard Worker 	};
148*387f9dfdSAndroid Build Coastguard Worker 	struct vfsstat_bpf *skel;
149*387f9dfdSAndroid Build Coastguard Worker 	int err;
150*387f9dfdSAndroid Build Coastguard Worker 
151*387f9dfdSAndroid Build Coastguard Worker 	err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
152*387f9dfdSAndroid Build Coastguard Worker 	if (err)
153*387f9dfdSAndroid Build Coastguard Worker 		return err;
154*387f9dfdSAndroid Build Coastguard Worker 
155*387f9dfdSAndroid Build Coastguard Worker 	libbpf_set_print(libbpf_print_fn);
156*387f9dfdSAndroid Build Coastguard Worker 
157*387f9dfdSAndroid Build Coastguard Worker 
158*387f9dfdSAndroid Build Coastguard Worker 	err = ensure_core_btf(&open_opts);
159*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
160*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to fetch necessary BTF for CO-RE: %s\n", strerror(-err));
161*387f9dfdSAndroid Build Coastguard Worker 		return 1;
162*387f9dfdSAndroid Build Coastguard Worker 	}
163*387f9dfdSAndroid Build Coastguard Worker 
164*387f9dfdSAndroid Build Coastguard Worker 	skel = vfsstat_bpf__open();
165*387f9dfdSAndroid Build Coastguard Worker 	if (!skel) {
166*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to open BPF skelect\n");
167*387f9dfdSAndroid Build Coastguard Worker 		return 1;
168*387f9dfdSAndroid Build Coastguard Worker 	}
169*387f9dfdSAndroid Build Coastguard Worker 
170*387f9dfdSAndroid Build Coastguard Worker 	/* It fallbacks to kprobes when kernel does not support fentry. */
171*387f9dfdSAndroid Build Coastguard Worker 	if (fentry_can_attach("vfs_read", NULL)) {
172*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.kprobe_vfs_read, false);
173*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.kprobe_vfs_write, false);
174*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.kprobe_vfs_fsync, false);
175*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.kprobe_vfs_open, false);
176*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.kprobe_vfs_create, false);
177*387f9dfdSAndroid Build Coastguard Worker 	} else {
178*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.fentry_vfs_read, false);
179*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.fentry_vfs_write, false);
180*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.fentry_vfs_fsync, false);
181*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.fentry_vfs_open, false);
182*387f9dfdSAndroid Build Coastguard Worker 		bpf_program__set_autoload(skel->progs.fentry_vfs_create, false);
183*387f9dfdSAndroid Build Coastguard Worker 	}
184*387f9dfdSAndroid Build Coastguard Worker 
185*387f9dfdSAndroid Build Coastguard Worker 	err = vfsstat_bpf__load(skel);
186*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
187*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to load BPF skelect: %d\n", err);
188*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
189*387f9dfdSAndroid Build Coastguard Worker 	}
190*387f9dfdSAndroid Build Coastguard Worker 
191*387f9dfdSAndroid Build Coastguard Worker 	if (!skel->bss) {
192*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "Memory-mapping BPF maps is supported starting from Linux 5.7, please upgrade.\n");
193*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
194*387f9dfdSAndroid Build Coastguard Worker 	}
195*387f9dfdSAndroid Build Coastguard Worker 
196*387f9dfdSAndroid Build Coastguard Worker 	err = vfsstat_bpf__attach(skel);
197*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
198*387f9dfdSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to attach BPF programs: %s\n",
199*387f9dfdSAndroid Build Coastguard Worker 				strerror(-err));
200*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
201*387f9dfdSAndroid Build Coastguard Worker 	}
202*387f9dfdSAndroid Build Coastguard Worker 
203*387f9dfdSAndroid Build Coastguard Worker 	print_header();
204*387f9dfdSAndroid Build Coastguard Worker 	do {
205*387f9dfdSAndroid Build Coastguard Worker 		sleep(env.interval);
206*387f9dfdSAndroid Build Coastguard Worker 		print_and_reset_stats(skel->bss->stats);
207*387f9dfdSAndroid Build Coastguard Worker 	} while (!env.count || --env.count);
208*387f9dfdSAndroid Build Coastguard Worker 
209*387f9dfdSAndroid Build Coastguard Worker cleanup:
210*387f9dfdSAndroid Build Coastguard Worker 	vfsstat_bpf__destroy(skel);
211*387f9dfdSAndroid Build Coastguard Worker 	cleanup_core_btf(&open_opts);
212*387f9dfdSAndroid Build Coastguard Worker 
213*387f9dfdSAndroid Build Coastguard Worker 	return err != 0;
214*387f9dfdSAndroid Build Coastguard Worker }
215