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