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