1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <signal.h> 6 #include <string.h> 7 8 #include <bpf/bpf.h> 9 #include <bpf/libbpf.h> 10 #include "bpf_util.h" 11 12 #define MAX_INDEX 64 13 #define MAX_STARS 38 14 15 /* my_map, my_hist_map */ 16 static int map_fd[2]; 17 18 static void stars(char *str, long val, long max, int width) 19 { 20 int i; 21 22 for (i = 0; i < (width * val / max) - 1 && i < width - 1; i++) 23 str[i] = '*'; 24 if (val > max) 25 str[i - 1] = '+'; 26 str[i] = '\0'; 27 } 28 29 struct task { 30 char comm[16]; 31 __u64 pid_tgid; 32 __u64 uid_gid; 33 }; 34 35 struct hist_key { 36 struct task t; 37 __u32 index; 38 }; 39 40 #define SIZE sizeof(struct task) 41 42 static void print_hist_for_pid(int fd, void *task) 43 { 44 unsigned int nr_cpus = bpf_num_possible_cpus(); 45 struct hist_key key = {}, next_key; 46 long values[nr_cpus]; 47 char starstr[MAX_STARS]; 48 long value; 49 long data[MAX_INDEX] = {}; 50 int max_ind = -1; 51 long max_value = 0; 52 int i, ind; 53 54 while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { 55 if (memcmp(&next_key, task, SIZE)) { 56 key = next_key; 57 continue; 58 } 59 bpf_map_lookup_elem(fd, &next_key, values); 60 value = 0; 61 for (i = 0; i < nr_cpus; i++) 62 value += values[i]; 63 ind = next_key.index; 64 data[ind] = value; 65 if (value && ind > max_ind) 66 max_ind = ind; 67 if (value > max_value) 68 max_value = value; 69 key = next_key; 70 } 71 72 printf(" syscall write() stats\n"); 73 printf(" byte_size : count distribution\n"); 74 for (i = 1; i <= max_ind + 1; i++) { 75 stars(starstr, data[i - 1], max_value, MAX_STARS); 76 printf("%8ld -> %-8ld : %-8ld |%-*s|\n", 77 (1l << i) >> 1, (1l << i) - 1, data[i - 1], 78 MAX_STARS, starstr); 79 } 80 } 81 82 static void print_hist(int fd) 83 { 84 struct hist_key key = {}, next_key; 85 static struct task tasks[1024]; 86 int task_cnt = 0; 87 int i; 88 89 while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { 90 int found = 0; 91 92 for (i = 0; i < task_cnt; i++) 93 if (memcmp(&tasks[i], &next_key, SIZE) == 0) 94 found = 1; 95 if (!found) 96 memcpy(&tasks[task_cnt++], &next_key, SIZE); 97 key = next_key; 98 } 99 100 for (i = 0; i < task_cnt; i++) { 101 printf("\npid %d cmd %s uid %d\n", 102 (__u32) tasks[i].pid_tgid, 103 tasks[i].comm, 104 (__u32) tasks[i].uid_gid); 105 print_hist_for_pid(fd, &tasks[i]); 106 } 107 108 } 109 110 static void int_exit(int sig) 111 { 112 print_hist(map_fd[1]); 113 exit(0); 114 } 115 116 int main(int ac, char **argv) 117 { 118 long key, next_key, value; 119 struct bpf_link *links[2]; 120 struct bpf_program *prog; 121 struct bpf_object *obj; 122 char filename[256]; 123 int i, j = 0; 124 FILE *f; 125 126 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 127 obj = bpf_object__open_file(filename, NULL); 128 if (libbpf_get_error(obj)) { 129 fprintf(stderr, "ERROR: opening BPF object file failed\n"); 130 return 0; 131 } 132 133 /* load BPF program */ 134 if (bpf_object__load(obj)) { 135 fprintf(stderr, "ERROR: loading BPF object file failed\n"); 136 goto cleanup; 137 } 138 139 map_fd[0] = bpf_object__find_map_fd_by_name(obj, "my_map"); 140 map_fd[1] = bpf_object__find_map_fd_by_name(obj, "my_hist_map"); 141 if (map_fd[0] < 0 || map_fd[1] < 0) { 142 fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 143 goto cleanup; 144 } 145 146 signal(SIGINT, int_exit); 147 signal(SIGTERM, int_exit); 148 149 /* start 'ping' in the background to have some kfree_skb events */ 150 f = popen("ping -4 -c5 localhost", "r"); 151 (void) f; 152 153 /* start 'dd' in the background to have plenty of 'write' syscalls */ 154 f = popen("dd if=/dev/zero of=/dev/null count=5000000", "r"); 155 (void) f; 156 157 bpf_object__for_each_program(prog, obj) { 158 links[j] = bpf_program__attach(prog); 159 if (libbpf_get_error(links[j])) { 160 fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 161 links[j] = NULL; 162 goto cleanup; 163 } 164 j++; 165 } 166 167 for (i = 0; i < 5; i++) { 168 key = 0; 169 while (bpf_map_get_next_key(map_fd[0], &key, &next_key) == 0) { 170 bpf_map_lookup_elem(map_fd[0], &next_key, &value); 171 printf("location 0x%lx count %ld\n", next_key, value); 172 key = next_key; 173 } 174 if (key) 175 printf("\n"); 176 sleep(1); 177 } 178 print_hist(map_fd[1]); 179 180 cleanup: 181 for (j--; j >= 0; j--) 182 bpf_link__destroy(links[j]); 183 184 bpf_object__close(obj); 185 return 0; 186 } 187