18c2ecf20Sopenharmony_ci#!/bin/bash
28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci# Sergey Senozhatsky, 2015
58c2ecf20Sopenharmony_ci# sergey.senozhatsky.work@gmail.com
68c2ecf20Sopenharmony_ci#
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci# This program is intended to plot a `slabinfo -X' stats, collected,
108c2ecf20Sopenharmony_ci# for example, using the following command:
118c2ecf20Sopenharmony_ci#   while [ 1 ]; do slabinfo -X >> stats; sleep 1; done
128c2ecf20Sopenharmony_ci#
138c2ecf20Sopenharmony_ci# Use `slabinfo-gnuplot.sh stats' to pre-process collected records
148c2ecf20Sopenharmony_ci# and generate graphs (totals, slabs sorted by size, slabs sorted
158c2ecf20Sopenharmony_ci# by size).
168c2ecf20Sopenharmony_ci#
178c2ecf20Sopenharmony_ci# Graphs can be [individually] regenerate with different ranges and
188c2ecf20Sopenharmony_ci# size (-r %d,%d and -s %d,%d options).
198c2ecf20Sopenharmony_ci#
208c2ecf20Sopenharmony_ci# To visually compare N `totals' graphs, do
218c2ecf20Sopenharmony_ci# slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals
228c2ecf20Sopenharmony_ci#
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cimin_slab_name_size=11
258c2ecf20Sopenharmony_cixmin=0
268c2ecf20Sopenharmony_cixmax=0
278c2ecf20Sopenharmony_ciwidth=1500
288c2ecf20Sopenharmony_ciheight=700
298c2ecf20Sopenharmony_cimode=preprocess
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ciusage()
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	echo "Usage: [-s W,H] [-r MIN,MAX] [-t|-l] FILE1 [FILE2 ..]"
348c2ecf20Sopenharmony_ci	echo "FILEs must contain 'slabinfo -X' samples"
358c2ecf20Sopenharmony_ci	echo "-t 			- plot totals for FILE(s)"
368c2ecf20Sopenharmony_ci	echo "-l 			- plot slabs stats for FILE(s)"
378c2ecf20Sopenharmony_ci	echo "-s %d,%d		- set image width and height"
388c2ecf20Sopenharmony_ci	echo "-r %d,%d		- use data samples from a given range"
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cicheck_file_exist()
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	if [ ! -f "$1" ]; then
448c2ecf20Sopenharmony_ci		echo "File '$1' does not exist"
458c2ecf20Sopenharmony_ci		exit 1
468c2ecf20Sopenharmony_ci	fi
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cido_slabs_plotting()
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	local file=$1
528c2ecf20Sopenharmony_ci	local out_file
538c2ecf20Sopenharmony_ci	local range="every ::$xmin"
548c2ecf20Sopenharmony_ci	local xtic=""
558c2ecf20Sopenharmony_ci	local xtic_rotate="norotate"
568c2ecf20Sopenharmony_ci	local lines=2000000
578c2ecf20Sopenharmony_ci	local wc_lines
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	check_file_exist "$file"
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	out_file=`basename "$file"`
628c2ecf20Sopenharmony_ci	if [ $xmax -ne 0 ]; then
638c2ecf20Sopenharmony_ci		range="$range::$xmax"
648c2ecf20Sopenharmony_ci		lines=$((xmax-xmin))
658c2ecf20Sopenharmony_ci	fi
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	wc_lines=`cat "$file" | wc -l`
688c2ecf20Sopenharmony_ci	if [ $? -ne 0 ] || [ "$wc_lines" -eq 0 ] ; then
698c2ecf20Sopenharmony_ci		wc_lines=$lines
708c2ecf20Sopenharmony_ci	fi
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if [ "$wc_lines" -lt "$lines" ]; then
738c2ecf20Sopenharmony_ci		lines=$wc_lines
748c2ecf20Sopenharmony_ci	fi
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if [ $((width / lines)) -gt $min_slab_name_size ]; then
778c2ecf20Sopenharmony_ci		xtic=":xtic(1)"
788c2ecf20Sopenharmony_ci		xtic_rotate=90
798c2ecf20Sopenharmony_ci	fi
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cignuplot -p << EOF
828c2ecf20Sopenharmony_ci#!/usr/bin/env gnuplot
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ciset terminal png enhanced size $width,$height large
858c2ecf20Sopenharmony_ciset output '$out_file.png'
868c2ecf20Sopenharmony_ciset autoscale xy
878c2ecf20Sopenharmony_ciset xlabel 'samples'
888c2ecf20Sopenharmony_ciset ylabel 'bytes'
898c2ecf20Sopenharmony_ciset style histogram columnstacked title textcolor lt -1
908c2ecf20Sopenharmony_ciset style fill solid 0.15
918c2ecf20Sopenharmony_ciset xtics rotate $xtic_rotate
928c2ecf20Sopenharmony_ciset key left above Left title reverse
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ciplot "$file" $range u 2$xtic title 'SIZE' with boxes,\
958c2ecf20Sopenharmony_ci	'' $range u 3 title 'LOSS' with boxes
968c2ecf20Sopenharmony_ciEOF
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if [ $? -eq 0 ]; then
998c2ecf20Sopenharmony_ci		echo "$out_file.png"
1008c2ecf20Sopenharmony_ci	fi
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cido_totals_plotting()
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	local gnuplot_cmd=""
1068c2ecf20Sopenharmony_ci	local range="every ::$xmin"
1078c2ecf20Sopenharmony_ci	local file=""
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if [ $xmax -ne 0 ]; then
1108c2ecf20Sopenharmony_ci		range="$range::$xmax"
1118c2ecf20Sopenharmony_ci	fi
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	for i in "${t_files[@]}"; do
1148c2ecf20Sopenharmony_ci		check_file_exist "$i"
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		file="$file"`basename "$i"`
1178c2ecf20Sopenharmony_ci		gnuplot_cmd="$gnuplot_cmd '$i' $range using 1 title\
1188c2ecf20Sopenharmony_ci			'$i Memory usage' with lines,"
1198c2ecf20Sopenharmony_ci		gnuplot_cmd="$gnuplot_cmd '' $range using 2 title \
1208c2ecf20Sopenharmony_ci			'$i Loss' with lines,"
1218c2ecf20Sopenharmony_ci	done
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cignuplot -p << EOF
1248c2ecf20Sopenharmony_ci#!/usr/bin/env gnuplot
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciset terminal png enhanced size $width,$height large
1278c2ecf20Sopenharmony_ciset autoscale xy
1288c2ecf20Sopenharmony_ciset output '$file.png'
1298c2ecf20Sopenharmony_ciset xlabel 'samples'
1308c2ecf20Sopenharmony_ciset ylabel 'bytes'
1318c2ecf20Sopenharmony_ciset key left above Left title reverse
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciplot $gnuplot_cmd
1348c2ecf20Sopenharmony_ciEOF
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if [ $? -eq 0 ]; then
1378c2ecf20Sopenharmony_ci		echo "$file.png"
1388c2ecf20Sopenharmony_ci	fi
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cido_preprocess()
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	local out
1448c2ecf20Sopenharmony_ci	local lines
1458c2ecf20Sopenharmony_ci	local in=$1
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	check_file_exist "$in"
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	# use only 'TOP' slab (biggest memory usage or loss)
1508c2ecf20Sopenharmony_ci	let lines=3
1518c2ecf20Sopenharmony_ci	out=`basename "$in"`"-slabs-by-loss"
1528c2ecf20Sopenharmony_ci	`cat "$in" | grep -A "$lines" 'Slabs sorted by loss' |\
1538c2ecf20Sopenharmony_ci		grep -E -iv '\-\-|Name|Slabs'\
1548c2ecf20Sopenharmony_ci		| awk '{print $1" "$4+$2*$3" "$4}' > "$out"`
1558c2ecf20Sopenharmony_ci	if [ $? -eq 0 ]; then
1568c2ecf20Sopenharmony_ci		do_slabs_plotting "$out"
1578c2ecf20Sopenharmony_ci	fi
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	let lines=3
1608c2ecf20Sopenharmony_ci	out=`basename "$in"`"-slabs-by-size"
1618c2ecf20Sopenharmony_ci	`cat "$in" | grep -A "$lines" 'Slabs sorted by size' |\
1628c2ecf20Sopenharmony_ci		grep -E -iv '\-\-|Name|Slabs'\
1638c2ecf20Sopenharmony_ci		| awk '{print $1" "$4" "$4-$2*$3}' > "$out"`
1648c2ecf20Sopenharmony_ci	if [ $? -eq 0 ]; then
1658c2ecf20Sopenharmony_ci		do_slabs_plotting "$out"
1668c2ecf20Sopenharmony_ci	fi
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	out=`basename "$in"`"-totals"
1698c2ecf20Sopenharmony_ci	`cat "$in" | grep "Memory used" |\
1708c2ecf20Sopenharmony_ci		awk '{print $3" "$7}' > "$out"`
1718c2ecf20Sopenharmony_ci	if [ $? -eq 0 ]; then
1728c2ecf20Sopenharmony_ci		t_files[0]=$out
1738c2ecf20Sopenharmony_ci		do_totals_plotting
1748c2ecf20Sopenharmony_ci	fi
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ciparse_opts()
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	local opt
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	while getopts "tlr::s::h" opt; do
1828c2ecf20Sopenharmony_ci		case $opt in
1838c2ecf20Sopenharmony_ci			t)
1848c2ecf20Sopenharmony_ci				mode=totals
1858c2ecf20Sopenharmony_ci				;;
1868c2ecf20Sopenharmony_ci			l)
1878c2ecf20Sopenharmony_ci				mode=slabs
1888c2ecf20Sopenharmony_ci				;;
1898c2ecf20Sopenharmony_ci			s)
1908c2ecf20Sopenharmony_ci				array=(${OPTARG//,/ })
1918c2ecf20Sopenharmony_ci				width=${array[0]}
1928c2ecf20Sopenharmony_ci				height=${array[1]}
1938c2ecf20Sopenharmony_ci				;;
1948c2ecf20Sopenharmony_ci			r)
1958c2ecf20Sopenharmony_ci				array=(${OPTARG//,/ })
1968c2ecf20Sopenharmony_ci				xmin=${array[0]}
1978c2ecf20Sopenharmony_ci				xmax=${array[1]}
1988c2ecf20Sopenharmony_ci				;;
1998c2ecf20Sopenharmony_ci			h)
2008c2ecf20Sopenharmony_ci				usage
2018c2ecf20Sopenharmony_ci				exit 0
2028c2ecf20Sopenharmony_ci				;;
2038c2ecf20Sopenharmony_ci			\?)
2048c2ecf20Sopenharmony_ci				echo "Invalid option: -$OPTARG" >&2
2058c2ecf20Sopenharmony_ci				exit 1
2068c2ecf20Sopenharmony_ci				;;
2078c2ecf20Sopenharmony_ci			:)
2088c2ecf20Sopenharmony_ci				echo "-$OPTARG requires an argument." >&2
2098c2ecf20Sopenharmony_ci				exit 1
2108c2ecf20Sopenharmony_ci				;;
2118c2ecf20Sopenharmony_ci		esac
2128c2ecf20Sopenharmony_ci	done
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return $OPTIND
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ciparse_args()
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	local idx=0
2208c2ecf20Sopenharmony_ci	local p
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	for p in "$@"; do
2238c2ecf20Sopenharmony_ci		case $mode in
2248c2ecf20Sopenharmony_ci			preprocess)
2258c2ecf20Sopenharmony_ci				files[$idx]=$p
2268c2ecf20Sopenharmony_ci				idx=$idx+1
2278c2ecf20Sopenharmony_ci				;;
2288c2ecf20Sopenharmony_ci			totals)
2298c2ecf20Sopenharmony_ci				t_files[$idx]=$p
2308c2ecf20Sopenharmony_ci				idx=$idx+1
2318c2ecf20Sopenharmony_ci				;;
2328c2ecf20Sopenharmony_ci			slabs)
2338c2ecf20Sopenharmony_ci				files[$idx]=$p
2348c2ecf20Sopenharmony_ci				idx=$idx+1
2358c2ecf20Sopenharmony_ci				;;
2368c2ecf20Sopenharmony_ci		esac
2378c2ecf20Sopenharmony_ci	done
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ciparse_opts "$@"
2418c2ecf20Sopenharmony_ciargstart=$?
2428c2ecf20Sopenharmony_ciparse_args "${@:$argstart}"
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ciif [ ${#files[@]} -eq 0 ] && [ ${#t_files[@]} -eq 0 ]; then
2458c2ecf20Sopenharmony_ci	usage
2468c2ecf20Sopenharmony_ci	exit 1
2478c2ecf20Sopenharmony_cifi
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cicase $mode in
2508c2ecf20Sopenharmony_ci	preprocess)
2518c2ecf20Sopenharmony_ci		for i in "${files[@]}"; do
2528c2ecf20Sopenharmony_ci			do_preprocess "$i"
2538c2ecf20Sopenharmony_ci		done
2548c2ecf20Sopenharmony_ci		;;
2558c2ecf20Sopenharmony_ci	totals)
2568c2ecf20Sopenharmony_ci		do_totals_plotting
2578c2ecf20Sopenharmony_ci		;;
2588c2ecf20Sopenharmony_ci	slabs)
2598c2ecf20Sopenharmony_ci		for i in "${files[@]}"; do
2608c2ecf20Sopenharmony_ci			do_slabs_plotting "$i"
2618c2ecf20Sopenharmony_ci		done
2628c2ecf20Sopenharmony_ci		;;
2638c2ecf20Sopenharmony_ci	*)
2648c2ecf20Sopenharmony_ci		echo "Unknown mode $mode" >&2
2658c2ecf20Sopenharmony_ci		usage
2668c2ecf20Sopenharmony_ci		exit 1
2678c2ecf20Sopenharmony_ci	;;
2688c2ecf20Sopenharmony_ciesac
269