18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci#include <stdio.h>
58c2ecf20Sopenharmony_ci#include <stdlib.h>
68c2ecf20Sopenharmony_ci#include <signal.h>
78c2ecf20Sopenharmony_ci#include <unistd.h>
88c2ecf20Sopenharmony_ci#include <stdbool.h>
98c2ecf20Sopenharmony_ci#include <string.h>
108c2ecf20Sopenharmony_ci#include <sys/resource.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
138c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
148c2ecf20Sopenharmony_ci#include "bpf_util.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define SLOTS 100
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic void clear_stats(int fd)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	unsigned int nr_cpus = bpf_num_possible_cpus();
218c2ecf20Sopenharmony_ci	__u64 values[nr_cpus];
228c2ecf20Sopenharmony_ci	__u32 key;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	memset(values, 0, sizeof(values));
258c2ecf20Sopenharmony_ci	for (key = 0; key < SLOTS; key++)
268c2ecf20Sopenharmony_ci		bpf_map_update_elem(fd, &key, values, BPF_ANY);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciconst char *color[] = {
308c2ecf20Sopenharmony_ci	"\033[48;5;255m",
318c2ecf20Sopenharmony_ci	"\033[48;5;252m",
328c2ecf20Sopenharmony_ci	"\033[48;5;250m",
338c2ecf20Sopenharmony_ci	"\033[48;5;248m",
348c2ecf20Sopenharmony_ci	"\033[48;5;246m",
358c2ecf20Sopenharmony_ci	"\033[48;5;244m",
368c2ecf20Sopenharmony_ci	"\033[48;5;242m",
378c2ecf20Sopenharmony_ci	"\033[48;5;240m",
388c2ecf20Sopenharmony_ci	"\033[48;5;238m",
398c2ecf20Sopenharmony_ci	"\033[48;5;236m",
408c2ecf20Sopenharmony_ci	"\033[48;5;234m",
418c2ecf20Sopenharmony_ci	"\033[48;5;232m",
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ciconst int num_colors = ARRAY_SIZE(color);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciconst char nocolor[] = "\033[00m";
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ciconst char *sym[] = {
488c2ecf20Sopenharmony_ci	" ",
498c2ecf20Sopenharmony_ci	" ",
508c2ecf20Sopenharmony_ci	".",
518c2ecf20Sopenharmony_ci	".",
528c2ecf20Sopenharmony_ci	"*",
538c2ecf20Sopenharmony_ci	"*",
548c2ecf20Sopenharmony_ci	"o",
558c2ecf20Sopenharmony_ci	"o",
568c2ecf20Sopenharmony_ci	"O",
578c2ecf20Sopenharmony_ci	"O",
588c2ecf20Sopenharmony_ci	"#",
598c2ecf20Sopenharmony_ci	"#",
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cibool full_range = false;
638c2ecf20Sopenharmony_cibool text_only = false;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic void print_banner(void)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	if (full_range)
688c2ecf20Sopenharmony_ci		printf("|1ns     |10ns     |100ns    |1us      |10us     |100us"
698c2ecf20Sopenharmony_ci		       "    |1ms      |10ms     |100ms    |1s       |10s\n");
708c2ecf20Sopenharmony_ci	else
718c2ecf20Sopenharmony_ci		printf("|1us      |10us     |100us    |1ms      |10ms     "
728c2ecf20Sopenharmony_ci		       "|100ms    |1s       |10s\n");
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void print_hist(int fd)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	unsigned int nr_cpus = bpf_num_possible_cpus();
788c2ecf20Sopenharmony_ci	__u64 total_events = 0;
798c2ecf20Sopenharmony_ci	long values[nr_cpus];
808c2ecf20Sopenharmony_ci	__u64 max_cnt = 0;
818c2ecf20Sopenharmony_ci	__u64 cnt[SLOTS];
828c2ecf20Sopenharmony_ci	__u64 value;
838c2ecf20Sopenharmony_ci	__u32 key;
848c2ecf20Sopenharmony_ci	int i;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	for (key = 0; key < SLOTS; key++) {
878c2ecf20Sopenharmony_ci		bpf_map_lookup_elem(fd, &key, values);
888c2ecf20Sopenharmony_ci		value = 0;
898c2ecf20Sopenharmony_ci		for (i = 0; i < nr_cpus; i++)
908c2ecf20Sopenharmony_ci			value += values[i];
918c2ecf20Sopenharmony_ci		cnt[key] = value;
928c2ecf20Sopenharmony_ci		total_events += value;
938c2ecf20Sopenharmony_ci		if (value > max_cnt)
948c2ecf20Sopenharmony_ci			max_cnt = value;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	clear_stats(fd);
978c2ecf20Sopenharmony_ci	for (key = full_range ? 0 : 29; key < SLOTS; key++) {
988c2ecf20Sopenharmony_ci		int c = num_colors * cnt[key] / (max_cnt + 1);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		if (text_only)
1018c2ecf20Sopenharmony_ci			printf("%s", sym[c]);
1028c2ecf20Sopenharmony_ci		else
1038c2ecf20Sopenharmony_ci			printf("%s %s", color[c], nocolor);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci	printf(" # %lld\n", total_events);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ciint main(int ac, char **argv)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
1118c2ecf20Sopenharmony_ci	struct bpf_link *links[2];
1128c2ecf20Sopenharmony_ci	struct bpf_program *prog;
1138c2ecf20Sopenharmony_ci	struct bpf_object *obj;
1148c2ecf20Sopenharmony_ci	char filename[256];
1158c2ecf20Sopenharmony_ci	int map_fd, i, j = 0;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	for (i = 1; i < ac; i++) {
1188c2ecf20Sopenharmony_ci		if (strcmp(argv[i], "-a") == 0) {
1198c2ecf20Sopenharmony_ci			full_range = true;
1208c2ecf20Sopenharmony_ci		} else if (strcmp(argv[i], "-t") == 0) {
1218c2ecf20Sopenharmony_ci			text_only = true;
1228c2ecf20Sopenharmony_ci		} else if (strcmp(argv[i], "-h") == 0) {
1238c2ecf20Sopenharmony_ci			printf("Usage:\n"
1248c2ecf20Sopenharmony_ci			       "  -a display wider latency range\n"
1258c2ecf20Sopenharmony_ci			       "  -t text only\n");
1268c2ecf20Sopenharmony_ci			return 1;
1278c2ecf20Sopenharmony_ci		}
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (setrlimit(RLIMIT_MEMLOCK, &r)) {
1318c2ecf20Sopenharmony_ci		perror("setrlimit(RLIMIT_MEMLOCK)");
1328c2ecf20Sopenharmony_ci		return 1;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
1368c2ecf20Sopenharmony_ci	obj = bpf_object__open_file(filename, NULL);
1378c2ecf20Sopenharmony_ci	if (libbpf_get_error(obj)) {
1388c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: opening BPF object file failed\n");
1398c2ecf20Sopenharmony_ci		return 0;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* load BPF program */
1438c2ecf20Sopenharmony_ci	if (bpf_object__load(obj)) {
1448c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: loading BPF object file failed\n");
1458c2ecf20Sopenharmony_ci		goto cleanup;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	map_fd = bpf_object__find_map_fd_by_name(obj, "lat_map");
1498c2ecf20Sopenharmony_ci	if (map_fd < 0) {
1508c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
1518c2ecf20Sopenharmony_ci		goto cleanup;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
1558c2ecf20Sopenharmony_ci		links[j] = bpf_program__attach(prog);
1568c2ecf20Sopenharmony_ci		if (libbpf_get_error(links[j])) {
1578c2ecf20Sopenharmony_ci			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
1588c2ecf20Sopenharmony_ci			links[j] = NULL;
1598c2ecf20Sopenharmony_ci			goto cleanup;
1608c2ecf20Sopenharmony_ci		}
1618c2ecf20Sopenharmony_ci		j++;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	printf("  heatmap of IO latency\n");
1658c2ecf20Sopenharmony_ci	if (text_only)
1668c2ecf20Sopenharmony_ci		printf("  %s", sym[num_colors - 1]);
1678c2ecf20Sopenharmony_ci	else
1688c2ecf20Sopenharmony_ci		printf("  %s %s", color[num_colors - 1], nocolor);
1698c2ecf20Sopenharmony_ci	printf(" - many events with this latency\n");
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (text_only)
1728c2ecf20Sopenharmony_ci		printf("  %s", sym[0]);
1738c2ecf20Sopenharmony_ci	else
1748c2ecf20Sopenharmony_ci		printf("  %s %s", color[0], nocolor);
1758c2ecf20Sopenharmony_ci	printf(" - few events\n");
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	for (i = 0; ; i++) {
1788c2ecf20Sopenharmony_ci		if (i % 20 == 0)
1798c2ecf20Sopenharmony_ci			print_banner();
1808c2ecf20Sopenharmony_ci		print_hist(map_fd);
1818c2ecf20Sopenharmony_ci		sleep(2);
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cicleanup:
1858c2ecf20Sopenharmony_ci	for (j--; j >= 0; j--)
1868c2ecf20Sopenharmony_ci		bpf_link__destroy(links[j]);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	bpf_object__close(obj);
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
191