1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com 3 * Copyright (c) 2015 BMW Car IT GmbH 4 */ 5 #include <stdio.h> 6 #include <unistd.h> 7 #include <stdlib.h> 8 #include <signal.h> 9 #include <bpf/libbpf.h> 10 #include <bpf/bpf.h> 11 12 #define MAX_ENTRIES 20 13 #define MAX_CPU 4 14 #define MAX_STARS 40 15 16 struct cpu_hist { 17 long data[MAX_ENTRIES]; 18 long max; 19 }; 20 21 static struct cpu_hist cpu_hist[MAX_CPU]; 22 23 static void stars(char *str, long val, long max, int width) 24 { 25 int i; 26 27 for (i = 0; i < (width * val / max) - 1 && i < width - 1; i++) 28 str[i] = '*'; 29 if (val > max) 30 str[i - 1] = '+'; 31 str[i] = '\0'; 32 } 33 34 static void print_hist(void) 35 { 36 char starstr[MAX_STARS]; 37 struct cpu_hist *hist; 38 int i, j; 39 40 /* clear screen */ 41 printf("\033[2J"); 42 43 for (j = 0; j < MAX_CPU; j++) { 44 hist = &cpu_hist[j]; 45 46 /* ignore CPUs without data (maybe offline?) */ 47 if (hist->max == 0) 48 continue; 49 50 printf("CPU %d\n", j); 51 printf(" latency : count distribution\n"); 52 for (i = 1; i <= MAX_ENTRIES; i++) { 53 stars(starstr, hist->data[i - 1], hist->max, MAX_STARS); 54 printf("%8ld -> %-8ld : %-8ld |%-*s|\n", 55 (1l << i) >> 1, (1l << i) - 1, 56 hist->data[i - 1], MAX_STARS, starstr); 57 } 58 } 59 } 60 61 static void get_data(int fd) 62 { 63 long key, value; 64 int c, i; 65 66 for (i = 0; i < MAX_CPU; i++) 67 cpu_hist[i].max = 0; 68 69 for (c = 0; c < MAX_CPU; c++) { 70 for (i = 0; i < MAX_ENTRIES; i++) { 71 key = c * MAX_ENTRIES + i; 72 bpf_map_lookup_elem(fd, &key, &value); 73 74 cpu_hist[c].data[i] = value; 75 if (value > cpu_hist[c].max) 76 cpu_hist[c].max = value; 77 } 78 } 79 } 80 81 int main(int argc, char **argv) 82 { 83 struct bpf_link *links[2]; 84 struct bpf_program *prog; 85 struct bpf_object *obj; 86 char filename[256]; 87 int map_fd, i = 0; 88 89 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 90 obj = bpf_object__open_file(filename, NULL); 91 if (libbpf_get_error(obj)) { 92 fprintf(stderr, "ERROR: opening BPF object file failed\n"); 93 return 0; 94 } 95 96 /* load BPF program */ 97 if (bpf_object__load(obj)) { 98 fprintf(stderr, "ERROR: loading BPF object file failed\n"); 99 goto cleanup; 100 } 101 102 map_fd = bpf_object__find_map_fd_by_name(obj, "my_lat"); 103 if (map_fd < 0) { 104 fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 105 goto cleanup; 106 } 107 108 bpf_object__for_each_program(prog, obj) { 109 links[i] = bpf_program__attach(prog); 110 if (libbpf_get_error(links[i])) { 111 fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 112 links[i] = NULL; 113 goto cleanup; 114 } 115 i++; 116 } 117 118 while (1) { 119 get_data(map_fd); 120 print_hist(); 121 sleep(5); 122 } 123 124 cleanup: 125 for (i--; i >= 0; i--) 126 bpf_link__destroy(links[i]); 127 128 bpf_object__close(obj); 129 return 0; 130 } 131