• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <argp.h>
7 #include <signal.h>
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <bpf/libbpf.h>
12 #include <bpf/bpf.h>
13 #include "numamove.skel.h"
14 #include "trace_helpers.h"
15 
16 static struct env {
17 	bool verbose;
18 } env;
19 
20 static volatile bool exiting;
21 
22 const char *argp_program_version = "numamove 0.1";
23 const char *argp_program_bug_address =
24 	"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
25 const char argp_program_doc[] =
26 "Show page migrations of type NUMA misplaced per second.\n"
27 "\n"
28 "USAGE: numamove [--help]\n"
29 "\n"
30 "EXAMPLES:\n"
31 "    numamove              # Show page migrations' count and latency";
32 
33 static const struct argp_option opts[] = {
34 	{ "verbose", 'v', NULL, 0, "Verbose debug output" },
35 	{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
36 	{},
37 };
38 
parse_arg(int key,char * arg,struct argp_state * state)39 static error_t parse_arg(int key, char *arg, struct argp_state *state)
40 {
41 	switch (key) {
42 	case 'h':
43 		argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
44 		break;
45 	case 'v':
46 		env.verbose = true;
47 		break;
48 	default:
49 		return ARGP_ERR_UNKNOWN;
50 	}
51 	return 0;
52 }
53 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)54 static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
55 {
56 	if (level == LIBBPF_DEBUG && !env.verbose)
57 		return 0;
58 	return vfprintf(stderr, format, args);
59 }
60 
sig_handler(int sig)61 static void sig_handler(int sig)
62 {
63 	exiting = true;
64 }
65 
main(int argc,char ** argv)66 int main(int argc, char **argv)
67 {
68 	static const struct argp argp = {
69 		.options = opts,
70 		.parser = parse_arg,
71 		.doc = argp_program_doc,
72 	};
73 	struct numamove_bpf *obj;
74 	struct tm *tm;
75 	char ts[32];
76 	time_t t;
77 	int err;
78 
79 	err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
80 	if (err)
81 		return err;
82 
83 	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
84 	libbpf_set_print(libbpf_print_fn);
85 
86 	obj = numamove_bpf__open_and_load();
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 	err = numamove_bpf__attach(obj);
98 	if (err) {
99 		fprintf(stderr, "failed to attach BPF programs\n");
100 		goto cleanup;
101 	}
102 
103 	signal(SIGINT, sig_handler);
104 
105 	printf("%-10s %18s %18s\n", "TIME", "NUMA_migrations", "NUMA_migrations_ms");
106 	while (!exiting) {
107 		sleep(1);
108 		time(&t);
109 		tm = localtime(&t);
110 		strftime(ts, sizeof(ts), "%H:%M:%S", tm);
111 		printf("%-10s %18lld %18lld\n", ts,
112 			__atomic_exchange_n(&obj->bss->num, 0, __ATOMIC_RELAXED),
113 			__atomic_exchange_n(&obj->bss->latency, 0, __ATOMIC_RELAXED));
114 	}
115 
116 cleanup:
117 	numamove_bpf__destroy(obj);
118 	return err != 0;
119 }
120