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