1/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <signal.h>
10#include <unistd.h>
11#include <stdbool.h>
12#include <string.h>
13#include <linux/bpf.h>
14#include "libbpf.h"
15#include "bpf_load.h"
16
17#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
18
19#define SLOTS 100
20
21static void clear_stats(int fd)
22{
23	__u32 key;
24	__u64 value = 0;
25
26	for (key = 0; key < SLOTS; key++)
27		bpf_update_elem(fd, &key, &value, BPF_ANY);
28}
29
30const char *color[] = {
31	"\033[48;5;255m",
32	"\033[48;5;252m",
33	"\033[48;5;250m",
34	"\033[48;5;248m",
35	"\033[48;5;246m",
36	"\033[48;5;244m",
37	"\033[48;5;242m",
38	"\033[48;5;240m",
39	"\033[48;5;238m",
40	"\033[48;5;236m",
41	"\033[48;5;234m",
42	"\033[48;5;232m",
43};
44const int num_colors = ARRAY_SIZE(color);
45
46const char nocolor[] = "\033[00m";
47
48const char *sym[] = {
49	" ",
50	" ",
51	".",
52	".",
53	"*",
54	"*",
55	"o",
56	"o",
57	"O",
58	"O",
59	"#",
60	"#",
61};
62
63bool full_range = false;
64bool text_only = false;
65
66static void print_banner(void)
67{
68	if (full_range)
69		printf("|1ns     |10ns     |100ns    |1us      |10us     |100us"
70		       "    |1ms      |10ms     |100ms    |1s       |10s\n");
71	else
72		printf("|1us      |10us     |100us    |1ms      |10ms     "
73		       "|100ms    |1s       |10s\n");
74}
75
76static void print_hist(int fd)
77{
78	__u32 key;
79	__u64 value;
80	__u64 cnt[SLOTS];
81	__u64 max_cnt = 0;
82	__u64 total_events = 0;
83
84	for (key = 0; key < SLOTS; key++) {
85		value = 0;
86		bpf_lookup_elem(fd, &key, &value);
87		cnt[key] = value;
88		total_events += value;
89		if (value > max_cnt)
90			max_cnt = value;
91	}
92	clear_stats(fd);
93	for (key = full_range ? 0 : 29; key < SLOTS; key++) {
94		int c = num_colors * cnt[key] / (max_cnt + 1);
95
96		if (text_only)
97			printf("%s", sym[c]);
98		else
99			printf("%s %s", color[c], nocolor);
100	}
101	printf(" # %lld\n", total_events);
102}
103
104int main(int ac, char **argv)
105{
106	char filename[256];
107	int i;
108
109	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
110
111	if (load_bpf_file(filename)) {
112		printf("%s", bpf_log_buf);
113		return 1;
114	}
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
129	printf("  heatmap of IO latency\n");
130	if (text_only)
131		printf("  %s", sym[num_colors - 1]);
132	else
133		printf("  %s %s", color[num_colors - 1], nocolor);
134	printf(" - many events with this latency\n");
135
136	if (text_only)
137		printf("  %s", sym[0]);
138	else
139		printf("  %s %s", color[0], nocolor);
140	printf(" - few events\n");
141
142	for (i = 0; ; i++) {
143		if (i % 20 == 0)
144			print_banner();
145		print_hist(map_fd[1]);
146		sleep(2);
147	}
148
149	return 0;
150}
151