125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20fb1170eSDaniel Wagner /* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
30fb1170eSDaniel Wagner * Copyright (c) 2015 BMW Car IT GmbH
40fb1170eSDaniel Wagner */
50fb1170eSDaniel Wagner #include <stdio.h>
60fb1170eSDaniel Wagner #include <unistd.h>
70fb1170eSDaniel Wagner #include <stdlib.h>
80fb1170eSDaniel Wagner #include <signal.h>
9*3677d0a1SDaniel T. Lee #include <bpf/libbpf.h>
102bf3e2efSJakub Kicinski #include <bpf/bpf.h>
110fb1170eSDaniel Wagner
120fb1170eSDaniel Wagner #define MAX_ENTRIES 20
130fb1170eSDaniel Wagner #define MAX_CPU 4
140fb1170eSDaniel Wagner #define MAX_STARS 40
150fb1170eSDaniel Wagner
160fb1170eSDaniel Wagner struct cpu_hist {
170fb1170eSDaniel Wagner long data[MAX_ENTRIES];
180fb1170eSDaniel Wagner long max;
190fb1170eSDaniel Wagner };
200fb1170eSDaniel Wagner
210fb1170eSDaniel Wagner static struct cpu_hist cpu_hist[MAX_CPU];
220fb1170eSDaniel Wagner
stars(char * str,long val,long max,int width)230fb1170eSDaniel Wagner static void stars(char *str, long val, long max, int width)
240fb1170eSDaniel Wagner {
250fb1170eSDaniel Wagner int i;
260fb1170eSDaniel Wagner
270fb1170eSDaniel Wagner for (i = 0; i < (width * val / max) - 1 && i < width - 1; i++)
280fb1170eSDaniel Wagner str[i] = '*';
290fb1170eSDaniel Wagner if (val > max)
300fb1170eSDaniel Wagner str[i - 1] = '+';
310fb1170eSDaniel Wagner str[i] = '\0';
320fb1170eSDaniel Wagner }
330fb1170eSDaniel Wagner
print_hist(void)340fb1170eSDaniel Wagner static void print_hist(void)
350fb1170eSDaniel Wagner {
360fb1170eSDaniel Wagner char starstr[MAX_STARS];
370fb1170eSDaniel Wagner struct cpu_hist *hist;
380fb1170eSDaniel Wagner int i, j;
390fb1170eSDaniel Wagner
400fb1170eSDaniel Wagner /* clear screen */
410fb1170eSDaniel Wagner printf("\033[2J");
420fb1170eSDaniel Wagner
430fb1170eSDaniel Wagner for (j = 0; j < MAX_CPU; j++) {
440fb1170eSDaniel Wagner hist = &cpu_hist[j];
450fb1170eSDaniel Wagner
460fb1170eSDaniel Wagner /* ignore CPUs without data (maybe offline?) */
470fb1170eSDaniel Wagner if (hist->max == 0)
480fb1170eSDaniel Wagner continue;
490fb1170eSDaniel Wagner
500fb1170eSDaniel Wagner printf("CPU %d\n", j);
510fb1170eSDaniel Wagner printf(" latency : count distribution\n");
520fb1170eSDaniel Wagner for (i = 1; i <= MAX_ENTRIES; i++) {
530fb1170eSDaniel Wagner stars(starstr, hist->data[i - 1], hist->max, MAX_STARS);
540fb1170eSDaniel Wagner printf("%8ld -> %-8ld : %-8ld |%-*s|\n",
550fb1170eSDaniel Wagner (1l << i) >> 1, (1l << i) - 1,
560fb1170eSDaniel Wagner hist->data[i - 1], MAX_STARS, starstr);
570fb1170eSDaniel Wagner }
580fb1170eSDaniel Wagner }
590fb1170eSDaniel Wagner }
600fb1170eSDaniel Wagner
get_data(int fd)610fb1170eSDaniel Wagner static void get_data(int fd)
620fb1170eSDaniel Wagner {
630fb1170eSDaniel Wagner long key, value;
640fb1170eSDaniel Wagner int c, i;
650fb1170eSDaniel Wagner
660fb1170eSDaniel Wagner for (i = 0; i < MAX_CPU; i++)
670fb1170eSDaniel Wagner cpu_hist[i].max = 0;
680fb1170eSDaniel Wagner
690fb1170eSDaniel Wagner for (c = 0; c < MAX_CPU; c++) {
700fb1170eSDaniel Wagner for (i = 0; i < MAX_ENTRIES; i++) {
710fb1170eSDaniel Wagner key = c * MAX_ENTRIES + i;
72d40fc181SJoe Stringer bpf_map_lookup_elem(fd, &key, &value);
730fb1170eSDaniel Wagner
740fb1170eSDaniel Wagner cpu_hist[c].data[i] = value;
750fb1170eSDaniel Wagner if (value > cpu_hist[c].max)
760fb1170eSDaniel Wagner cpu_hist[c].max = value;
770fb1170eSDaniel Wagner }
780fb1170eSDaniel Wagner }
790fb1170eSDaniel Wagner }
800fb1170eSDaniel Wagner
main(int argc,char ** argv)810fb1170eSDaniel Wagner int main(int argc, char **argv)
820fb1170eSDaniel Wagner {
83*3677d0a1SDaniel T. Lee struct bpf_link *links[2];
84*3677d0a1SDaniel T. Lee struct bpf_program *prog;
85*3677d0a1SDaniel T. Lee struct bpf_object *obj;
860fb1170eSDaniel Wagner char filename[256];
87*3677d0a1SDaniel T. Lee int map_fd, i = 0;
880fb1170eSDaniel Wagner
890fb1170eSDaniel Wagner snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
90*3677d0a1SDaniel T. Lee obj = bpf_object__open_file(filename, NULL);
91*3677d0a1SDaniel T. Lee if (libbpf_get_error(obj)) {
92*3677d0a1SDaniel T. Lee fprintf(stderr, "ERROR: opening BPF object file failed\n");
93*3677d0a1SDaniel T. Lee return 0;
94*3677d0a1SDaniel T. Lee }
950fb1170eSDaniel Wagner
96*3677d0a1SDaniel T. Lee /* load BPF program */
97*3677d0a1SDaniel T. Lee if (bpf_object__load(obj)) {
98*3677d0a1SDaniel T. Lee fprintf(stderr, "ERROR: loading BPF object file failed\n");
99*3677d0a1SDaniel T. Lee goto cleanup;
100*3677d0a1SDaniel T. Lee }
101*3677d0a1SDaniel T. Lee
102*3677d0a1SDaniel T. Lee map_fd = bpf_object__find_map_fd_by_name(obj, "my_lat");
103*3677d0a1SDaniel T. Lee if (map_fd < 0) {
104*3677d0a1SDaniel T. Lee fprintf(stderr, "ERROR: finding a map in obj file failed\n");
105*3677d0a1SDaniel T. Lee goto cleanup;
106*3677d0a1SDaniel T. Lee }
107*3677d0a1SDaniel T. Lee
108*3677d0a1SDaniel T. Lee bpf_object__for_each_program(prog, obj) {
109*3677d0a1SDaniel T. Lee links[i] = bpf_program__attach(prog);
110*3677d0a1SDaniel T. Lee if (libbpf_get_error(links[i])) {
111*3677d0a1SDaniel T. Lee fprintf(stderr, "ERROR: bpf_program__attach failed\n");
112*3677d0a1SDaniel T. Lee links[i] = NULL;
113*3677d0a1SDaniel T. Lee goto cleanup;
114*3677d0a1SDaniel T. Lee }
115*3677d0a1SDaniel T. Lee i++;
1160fb1170eSDaniel Wagner }
1170fb1170eSDaniel Wagner
1180fb1170eSDaniel Wagner while (1) {
119*3677d0a1SDaniel T. Lee get_data(map_fd);
1200fb1170eSDaniel Wagner print_hist();
1210fb1170eSDaniel Wagner sleep(5);
1220fb1170eSDaniel Wagner }
1230fb1170eSDaniel Wagner
124*3677d0a1SDaniel T. Lee cleanup:
125*3677d0a1SDaniel T. Lee for (i--; i >= 0; i--)
126*3677d0a1SDaniel T. Lee bpf_link__destroy(links[i]);
127*3677d0a1SDaniel T. Lee
128*3677d0a1SDaniel T. Lee bpf_object__close(obj);
1290fb1170eSDaniel Wagner return 0;
1300fb1170eSDaniel Wagner }
131