Commit | Line | Data |
---|---|---|
25763b3c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
5c7fc2d2 | 2 | /* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com |
5c7fc2d2 AS |
3 | */ |
4 | #include <stdio.h> | |
5 | #include <stdlib.h> | |
6 | #include <signal.h> | |
7 | #include <unistd.h> | |
8 | #include <stdbool.h> | |
9 | #include <string.h> | |
55de1703 | 10 | #include <sys/resource.h> |
e00c7b21 | 11 | |
2bf3e2ef | 12 | #include <bpf/bpf.h> |
63841bc0 | 13 | #include <bpf/libbpf.h> |
e00c7b21 | 14 | #include "bpf_util.h" |
5c7fc2d2 | 15 | |
5c7fc2d2 AS |
16 | #define SLOTS 100 |
17 | ||
18 | static void clear_stats(int fd) | |
19 | { | |
e00c7b21 | 20 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
3059303f | 21 | __u64 values[nr_cpus]; |
5c7fc2d2 | 22 | __u32 key; |
5c7fc2d2 | 23 | |
3059303f | 24 | memset(values, 0, sizeof(values)); |
5c7fc2d2 | 25 | for (key = 0; key < SLOTS; key++) |
d40fc181 | 26 | bpf_map_update_elem(fd, &key, values, BPF_ANY); |
5c7fc2d2 AS |
27 | } |
28 | ||
29 | const char *color[] = { | |
30 | "\033[48;5;255m", | |
31 | "\033[48;5;252m", | |
32 | "\033[48;5;250m", | |
33 | "\033[48;5;248m", | |
34 | "\033[48;5;246m", | |
35 | "\033[48;5;244m", | |
36 | "\033[48;5;242m", | |
37 | "\033[48;5;240m", | |
38 | "\033[48;5;238m", | |
39 | "\033[48;5;236m", | |
40 | "\033[48;5;234m", | |
41 | "\033[48;5;232m", | |
42 | }; | |
43 | const int num_colors = ARRAY_SIZE(color); | |
44 | ||
45 | const char nocolor[] = "\033[00m"; | |
46 | ||
47 | const char *sym[] = { | |
48 | " ", | |
49 | " ", | |
50 | ".", | |
51 | ".", | |
52 | "*", | |
53 | "*", | |
54 | "o", | |
55 | "o", | |
56 | "O", | |
57 | "O", | |
58 | "#", | |
59 | "#", | |
60 | }; | |
61 | ||
62 | bool full_range = false; | |
63 | bool text_only = false; | |
64 | ||
65 | static void print_banner(void) | |
66 | { | |
67 | if (full_range) | |
68 | printf("|1ns |10ns |100ns |1us |10us |100us" | |
69 | " |1ms |10ms |100ms |1s |10s\n"); | |
70 | else | |
71 | printf("|1us |10us |100us |1ms |10ms " | |
72 | "|100ms |1s |10s\n"); | |
73 | } | |
74 | ||
75 | static void print_hist(int fd) | |
76 | { | |
e00c7b21 | 77 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
5c7fc2d2 | 78 | __u64 total_events = 0; |
3059303f AS |
79 | long values[nr_cpus]; |
80 | __u64 max_cnt = 0; | |
81 | __u64 cnt[SLOTS]; | |
82 | __u64 value; | |
83 | __u32 key; | |
84 | int i; | |
5c7fc2d2 AS |
85 | |
86 | for (key = 0; key < SLOTS; key++) { | |
d40fc181 | 87 | bpf_map_lookup_elem(fd, &key, values); |
5c7fc2d2 | 88 | value = 0; |
3059303f AS |
89 | for (i = 0; i < nr_cpus; i++) |
90 | value += values[i]; | |
5c7fc2d2 AS |
91 | cnt[key] = value; |
92 | total_events += value; | |
93 | if (value > max_cnt) | |
94 | max_cnt = value; | |
95 | } | |
96 | clear_stats(fd); | |
97 | for (key = full_range ? 0 : 29; key < SLOTS; key++) { | |
98 | int c = num_colors * cnt[key] / (max_cnt + 1); | |
99 | ||
100 | if (text_only) | |
101 | printf("%s", sym[c]); | |
102 | else | |
103 | printf("%s %s", color[c], nocolor); | |
104 | } | |
105 | printf(" # %lld\n", total_events); | |
106 | } | |
107 | ||
108 | int main(int ac, char **argv) | |
109 | { | |
63841bc0 DL |
110 | struct bpf_link *links[2]; |
111 | struct bpf_program *prog; | |
112 | struct bpf_object *obj; | |
5c7fc2d2 | 113 | char filename[256]; |
63841bc0 | 114 | int map_fd, i, j = 0; |
5c7fc2d2 AS |
115 | |
116 | for (i = 1; i < ac; i++) { | |
117 | if (strcmp(argv[i], "-a") == 0) { | |
118 | full_range = true; | |
119 | } else if (strcmp(argv[i], "-t") == 0) { | |
120 | text_only = true; | |
121 | } else if (strcmp(argv[i], "-h") == 0) { | |
122 | printf("Usage:\n" | |
123 | " -a display wider latency range\n" | |
124 | " -t text only\n"); | |
125 | return 1; | |
126 | } | |
127 | } | |
128 | ||
63841bc0 DL |
129 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); |
130 | obj = bpf_object__open_file(filename, NULL); | |
131 | if (libbpf_get_error(obj)) { | |
132 | fprintf(stderr, "ERROR: opening BPF object file failed\n"); | |
133 | return 0; | |
134 | } | |
135 | ||
136 | /* load BPF program */ | |
137 | if (bpf_object__load(obj)) { | |
138 | fprintf(stderr, "ERROR: loading BPF object file failed\n"); | |
139 | goto cleanup; | |
140 | } | |
141 | ||
142 | map_fd = bpf_object__find_map_fd_by_name(obj, "lat_map"); | |
143 | if (map_fd < 0) { | |
144 | fprintf(stderr, "ERROR: finding a map in obj file failed\n"); | |
145 | goto cleanup; | |
146 | } | |
147 | ||
148 | bpf_object__for_each_program(prog, obj) { | |
149 | links[j] = bpf_program__attach(prog); | |
150 | if (libbpf_get_error(links[j])) { | |
151 | fprintf(stderr, "ERROR: bpf_program__attach failed\n"); | |
152 | links[j] = NULL; | |
153 | goto cleanup; | |
154 | } | |
155 | j++; | |
156 | } | |
157 | ||
5c7fc2d2 AS |
158 | printf(" heatmap of IO latency\n"); |
159 | if (text_only) | |
160 | printf(" %s", sym[num_colors - 1]); | |
161 | else | |
162 | printf(" %s %s", color[num_colors - 1], nocolor); | |
163 | printf(" - many events with this latency\n"); | |
164 | ||
165 | if (text_only) | |
166 | printf(" %s", sym[0]); | |
167 | else | |
168 | printf(" %s %s", color[0], nocolor); | |
169 | printf(" - few events\n"); | |
170 | ||
171 | for (i = 0; ; i++) { | |
172 | if (i % 20 == 0) | |
173 | print_banner(); | |
63841bc0 | 174 | print_hist(map_fd); |
5c7fc2d2 AS |
175 | sleep(2); |
176 | } | |
177 | ||
63841bc0 DL |
178 | cleanup: |
179 | for (j--; j >= 0; j--) | |
180 | bpf_link__destroy(links[j]); | |
181 | ||
182 | bpf_object__close(obj); | |
5c7fc2d2 AS |
183 | return 0; |
184 | } |