162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci#include <stdio.h>
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <signal.h>
762306a36Sopenharmony_ci#include <unistd.h>
862306a36Sopenharmony_ci#include <stdbool.h>
962306a36Sopenharmony_ci#include <string.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <bpf/bpf.h>
1262306a36Sopenharmony_ci#include <bpf/libbpf.h>
1362306a36Sopenharmony_ci#include "bpf_util.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define SLOTS 100
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic void clear_stats(int fd)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	unsigned int nr_cpus = bpf_num_possible_cpus();
2062306a36Sopenharmony_ci	__u64 values[nr_cpus];
2162306a36Sopenharmony_ci	__u32 key;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	memset(values, 0, sizeof(values));
2462306a36Sopenharmony_ci	for (key = 0; key < SLOTS; key++)
2562306a36Sopenharmony_ci		bpf_map_update_elem(fd, &key, values, BPF_ANY);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciconst char *color[] = {
2962306a36Sopenharmony_ci	"\033[48;5;255m",
3062306a36Sopenharmony_ci	"\033[48;5;252m",
3162306a36Sopenharmony_ci	"\033[48;5;250m",
3262306a36Sopenharmony_ci	"\033[48;5;248m",
3362306a36Sopenharmony_ci	"\033[48;5;246m",
3462306a36Sopenharmony_ci	"\033[48;5;244m",
3562306a36Sopenharmony_ci	"\033[48;5;242m",
3662306a36Sopenharmony_ci	"\033[48;5;240m",
3762306a36Sopenharmony_ci	"\033[48;5;238m",
3862306a36Sopenharmony_ci	"\033[48;5;236m",
3962306a36Sopenharmony_ci	"\033[48;5;234m",
4062306a36Sopenharmony_ci	"\033[48;5;232m",
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ciconst int num_colors = ARRAY_SIZE(color);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ciconst char nocolor[] = "\033[00m";
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciconst char *sym[] = {
4762306a36Sopenharmony_ci	" ",
4862306a36Sopenharmony_ci	" ",
4962306a36Sopenharmony_ci	".",
5062306a36Sopenharmony_ci	".",
5162306a36Sopenharmony_ci	"*",
5262306a36Sopenharmony_ci	"*",
5362306a36Sopenharmony_ci	"o",
5462306a36Sopenharmony_ci	"o",
5562306a36Sopenharmony_ci	"O",
5662306a36Sopenharmony_ci	"O",
5762306a36Sopenharmony_ci	"#",
5862306a36Sopenharmony_ci	"#",
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cibool full_range = false;
6262306a36Sopenharmony_cibool text_only = false;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void print_banner(void)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	if (full_range)
6762306a36Sopenharmony_ci		printf("|1ns     |10ns     |100ns    |1us      |10us     |100us"
6862306a36Sopenharmony_ci		       "    |1ms      |10ms     |100ms    |1s       |10s\n");
6962306a36Sopenharmony_ci	else
7062306a36Sopenharmony_ci		printf("|1us      |10us     |100us    |1ms      |10ms     "
7162306a36Sopenharmony_ci		       "|100ms    |1s       |10s\n");
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void print_hist(int fd)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	unsigned int nr_cpus = bpf_num_possible_cpus();
7762306a36Sopenharmony_ci	__u64 total_events = 0;
7862306a36Sopenharmony_ci	long values[nr_cpus];
7962306a36Sopenharmony_ci	__u64 max_cnt = 0;
8062306a36Sopenharmony_ci	__u64 cnt[SLOTS];
8162306a36Sopenharmony_ci	__u64 value;
8262306a36Sopenharmony_ci	__u32 key;
8362306a36Sopenharmony_ci	int i;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	for (key = 0; key < SLOTS; key++) {
8662306a36Sopenharmony_ci		bpf_map_lookup_elem(fd, &key, values);
8762306a36Sopenharmony_ci		value = 0;
8862306a36Sopenharmony_ci		for (i = 0; i < nr_cpus; i++)
8962306a36Sopenharmony_ci			value += values[i];
9062306a36Sopenharmony_ci		cnt[key] = value;
9162306a36Sopenharmony_ci		total_events += value;
9262306a36Sopenharmony_ci		if (value > max_cnt)
9362306a36Sopenharmony_ci			max_cnt = value;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci	clear_stats(fd);
9662306a36Sopenharmony_ci	for (key = full_range ? 0 : 29; key < SLOTS; key++) {
9762306a36Sopenharmony_ci		int c = num_colors * cnt[key] / (max_cnt + 1);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		if (text_only)
10062306a36Sopenharmony_ci			printf("%s", sym[c]);
10162306a36Sopenharmony_ci		else
10262306a36Sopenharmony_ci			printf("%s %s", color[c], nocolor);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci	printf(" # %lld\n", total_events);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ciint main(int ac, char **argv)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct bpf_link *links[2];
11062306a36Sopenharmony_ci	struct bpf_program *prog;
11162306a36Sopenharmony_ci	struct bpf_object *obj;
11262306a36Sopenharmony_ci	char filename[256];
11362306a36Sopenharmony_ci	int map_fd, i, j = 0;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	for (i = 1; i < ac; i++) {
11662306a36Sopenharmony_ci		if (strcmp(argv[i], "-a") == 0) {
11762306a36Sopenharmony_ci			full_range = true;
11862306a36Sopenharmony_ci		} else if (strcmp(argv[i], "-t") == 0) {
11962306a36Sopenharmony_ci			text_only = true;
12062306a36Sopenharmony_ci		} else if (strcmp(argv[i], "-h") == 0) {
12162306a36Sopenharmony_ci			printf("Usage:\n"
12262306a36Sopenharmony_ci			       "  -a display wider latency range\n"
12362306a36Sopenharmony_ci			       "  -t text only\n");
12462306a36Sopenharmony_ci			return 1;
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]);
12962306a36Sopenharmony_ci	obj = bpf_object__open_file(filename, NULL);
13062306a36Sopenharmony_ci	if (libbpf_get_error(obj)) {
13162306a36Sopenharmony_ci		fprintf(stderr, "ERROR: opening BPF object file failed\n");
13262306a36Sopenharmony_ci		return 0;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* load BPF program */
13662306a36Sopenharmony_ci	if (bpf_object__load(obj)) {
13762306a36Sopenharmony_ci		fprintf(stderr, "ERROR: loading BPF object file failed\n");
13862306a36Sopenharmony_ci		goto cleanup;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	map_fd = bpf_object__find_map_fd_by_name(obj, "lat_map");
14262306a36Sopenharmony_ci	if (map_fd < 0) {
14362306a36Sopenharmony_ci		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
14462306a36Sopenharmony_ci		goto cleanup;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
14862306a36Sopenharmony_ci		links[j] = bpf_program__attach(prog);
14962306a36Sopenharmony_ci		if (libbpf_get_error(links[j])) {
15062306a36Sopenharmony_ci			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
15162306a36Sopenharmony_ci			links[j] = NULL;
15262306a36Sopenharmony_ci			goto cleanup;
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci		j++;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	printf("  heatmap of IO latency\n");
15862306a36Sopenharmony_ci	if (text_only)
15962306a36Sopenharmony_ci		printf("  %s", sym[num_colors - 1]);
16062306a36Sopenharmony_ci	else
16162306a36Sopenharmony_ci		printf("  %s %s", color[num_colors - 1], nocolor);
16262306a36Sopenharmony_ci	printf(" - many events with this latency\n");
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (text_only)
16562306a36Sopenharmony_ci		printf("  %s", sym[0]);
16662306a36Sopenharmony_ci	else
16762306a36Sopenharmony_ci		printf("  %s %s", color[0], nocolor);
16862306a36Sopenharmony_ci	printf(" - few events\n");
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	for (i = 0; ; i++) {
17162306a36Sopenharmony_ci		if (i % 20 == 0)
17262306a36Sopenharmony_ci			print_banner();
17362306a36Sopenharmony_ci		print_hist(map_fd);
17462306a36Sopenharmony_ci		sleep(2);
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cicleanup:
17862306a36Sopenharmony_ci	for (j--; j >= 0; j--)
17962306a36Sopenharmony_ci		bpf_link__destroy(links[j]);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	bpf_object__close(obj);
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci}
184