1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 // Copyright (c) 2020 Wenbo Zhang
3 //
4 // Based on numamove(8) from BPF-Perf-Tools-Book by Brendan Gregg.
5 // 8-Jun-2020 Wenbo Zhang Created this.
6 // 30-Jan-2023 Rong Tao Use fentry_can_attach() to decide use fentry/kprobe.
7 #include <argp.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <time.h>
12 #include <bpf/libbpf.h>
13 #include <bpf/bpf.h>
14 #include "numamove.skel.h"
15 #include "trace_helpers.h"
16
17 static struct env {
18 bool verbose;
19 } env;
20
21 static volatile bool exiting;
22
23 const char *argp_program_version = "numamove 0.1";
24 const char *argp_program_bug_address =
25 "https://github.com/iovisor/bcc/tree/master/libbpf-tools";
26 const char argp_program_doc[] =
27 "Show page migrations of type NUMA misplaced per second.\n"
28 "\n"
29 "USAGE: numamove [--help]\n"
30 "\n"
31 "EXAMPLES:\n"
32 " numamove # Show page migrations' count and latency";
33
34 static const struct argp_option opts[] = {
35 { "verbose", 'v', NULL, 0, "Verbose debug output" },
36 { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
37 {},
38 };
39
parse_arg(int key,char * arg,struct argp_state * state)40 static error_t parse_arg(int key, char *arg, struct argp_state *state)
41 {
42 switch (key) {
43 case 'h':
44 argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
45 break;
46 case 'v':
47 env.verbose = true;
48 break;
49 default:
50 return ARGP_ERR_UNKNOWN;
51 }
52 return 0;
53 }
54
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)55 static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
56 {
57 if (level == LIBBPF_DEBUG && !env.verbose)
58 return 0;
59 return vfprintf(stderr, format, args);
60 }
61
sig_handler(int sig)62 static void sig_handler(int sig)
63 {
64 exiting = true;
65 }
66
main(int argc,char ** argv)67 int main(int argc, char **argv)
68 {
69 static const struct argp argp = {
70 .options = opts,
71 .parser = parse_arg,
72 .doc = argp_program_doc,
73 };
74 struct numamove_bpf *obj;
75 struct tm *tm;
76 char ts[32];
77 time_t t;
78 int err;
79
80 err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
81 if (err)
82 return err;
83
84 libbpf_set_print(libbpf_print_fn);
85
86 obj = numamove_bpf__open();
87 if (!obj) {
88 fprintf(stderr, "failed to open and/or load BPF object\n");
89 return 1;
90 }
91
92 if (!obj->bss) {
93 fprintf(stderr, "Memory-mapping BPF maps is supported starting from Linux 5.7, please upgrade.\n");
94 goto cleanup;
95 }
96
97 /* It fallbacks to kprobes when kernel does not support fentry. */
98 if (fentry_can_attach("migrate_misplaced_page", NULL)) {
99 bpf_program__set_autoload(obj->progs.kprobe_migrate_misplaced_page, false);
100 bpf_program__set_autoload(obj->progs.kretprobe_migrate_misplaced_page_exit, false);
101 } else {
102 bpf_program__set_autoload(obj->progs.fentry_migrate_misplaced_page, false);
103 bpf_program__set_autoload(obj->progs.fexit_migrate_misplaced_page_exit, false);
104 }
105
106 err = numamove_bpf__load(obj);
107 if (err) {
108 fprintf(stderr, "failed to load BPF skelect: %d\n", err);
109 goto cleanup;
110 }
111
112 err = numamove_bpf__attach(obj);
113 if (err) {
114 fprintf(stderr, "failed to attach BPF programs\n");
115 goto cleanup;
116 }
117
118 signal(SIGINT, sig_handler);
119
120 printf("%-10s %18s %18s\n", "TIME", "NUMA_migrations", "NUMA_migrations_ms");
121 while (!exiting) {
122 sleep(1);
123 time(&t);
124 tm = localtime(&t);
125 strftime(ts, sizeof(ts), "%H:%M:%S", tm);
126 printf("%-10s %18lld %18lld\n", ts,
127 __atomic_exchange_n(&obj->bss->num, 0, __ATOMIC_RELAXED),
128 __atomic_exchange_n(&obj->bss->latency, 0, __ATOMIC_RELAXED));
129 }
130
131 cleanup:
132 numamove_bpf__destroy(obj);
133 return err != 0;
134 }
135