Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269#!/bin/bash# SPDX-License-Identifier: GPL-2.0-only
# Sergey Senozhatsky, 2015# sergey.senozhatsky.work@gmail.com#
# This program is intended to plot a `slabinfo -X' stats, collected,# for example, using the following command:# while [ 1 ]; do slabinfo -X >> stats; sleep 1; done## Use `slabinfo-gnuplot.sh stats' to pre-process collected records# and generate graphs (totals, slabs sorted by size, slabs sorted# by size).## Graphs can be [individually] regenerate with different ranges and# size (-r %d,%d and -s %d,%d options).## To visually compare N `totals' graphs, do# slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals#
min_slab_name_size=11xmin=0xmax=0width=1500height=700mode=preprocess
usage(){ echo "Usage: [-s W,H] [-r MIN,MAX] [-t|-l] FILE1 [FILE2 ..]" echo "FILEs must contain 'slabinfo -X' samples" echo "-t - plot totals for FILE(s)" echo "-l - plot slabs stats for FILE(s)" echo "-s %d,%d - set image width and height" echo "-r %d,%d - use data samples from a given range"}
check_file_exist(){ if [ ! -f "$1" ]; then echo "File '$1' does not exist" exit 1 fi}
do_slabs_plotting(){ local file=$1 local out_file local range="every ::$xmin" local xtic="" local xtic_rotate="norotate" local lines=2000000 local wc_lines
check_file_exist "$file"
out_file=`basename "$file"` if [ $xmax -ne 0 ]; then range="$range::$xmax" lines=$((xmax-xmin)) fi
wc_lines=`cat "$file" | wc -l` if [ $? -ne 0 ] || [ "$wc_lines" -eq 0 ] ; then wc_lines=$lines fi
if [ "$wc_lines" -lt "$lines" ]; then lines=$wc_lines fi
if [ $((width / lines)) -gt $min_slab_name_size ]; then xtic=":xtic(1)" xtic_rotate=90 fi
gnuplot -p << EOF#!/usr/bin/env gnuplot
set terminal png enhanced size $width,$height largeset output '$out_file.png'set autoscale xyset xlabel 'samples'set ylabel 'bytes'set style histogram columnstacked title textcolor lt -1set style fill solid 0.15set xtics rotate $xtic_rotateset key left above Left title reverse
plot "$file" $range u 2$xtic title 'SIZE' with boxes,\ '' $range u 3 title 'LOSS' with boxesEOF
if [ $? -eq 0 ]; then echo "$out_file.png" fi}
do_totals_plotting(){ local gnuplot_cmd="" local range="every ::$xmin" local file=""
if [ $xmax -ne 0 ]; then range="$range::$xmax" fi
for i in "${t_files[@]}"; do check_file_exist "$i"
file="$file"`basename "$i"` gnuplot_cmd="$gnuplot_cmd '$i' $range using 1 title\ '$i Memory usage' with lines," gnuplot_cmd="$gnuplot_cmd '' $range using 2 title \ '$i Loss' with lines," done
gnuplot -p << EOF#!/usr/bin/env gnuplot
set terminal png enhanced size $width,$height largeset autoscale xyset output '$file.png'set xlabel 'samples'set ylabel 'bytes'set key left above Left title reverse
plot $gnuplot_cmdEOF
if [ $? -eq 0 ]; then echo "$file.png" fi}
do_preprocess(){ local out local lines local in=$1
check_file_exist "$in"
# use only 'TOP' slab (biggest memory usage or loss) let lines=3 out=`basename "$in"`"-slabs-by-loss" `cat "$in" | grep -A "$lines" 'Slabs sorted by loss' |\ grep -E -iv '\-\-|Name|Slabs'\ | awk '{print $1" "$4+$2*$3" "$4}' > "$out"` if [ $? -eq 0 ]; then do_slabs_plotting "$out" fi
let lines=3 out=`basename "$in"`"-slabs-by-size" `cat "$in" | grep -A "$lines" 'Slabs sorted by size' |\ grep -E -iv '\-\-|Name|Slabs'\ | awk '{print $1" "$4" "$4-$2*$3}' > "$out"` if [ $? -eq 0 ]; then do_slabs_plotting "$out" fi
out=`basename "$in"`"-totals" `cat "$in" | grep "Memory used" |\ awk '{print $3" "$7}' > "$out"` if [ $? -eq 0 ]; then t_files[0]=$out do_totals_plotting fi}
parse_opts(){ local opt
while getopts "tlr::s::h" opt; do case $opt in t) mode=totals ;; l) mode=slabs ;; s) array=(${OPTARG//,/ }) width=${array[0]} height=${array[1]} ;; r) array=(${OPTARG//,/ }) xmin=${array[0]} xmax=${array[1]} ;; h) usage exit 0 ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "-$OPTARG requires an argument." >&2 exit 1 ;; esac done
return $OPTIND}
parse_args(){ local idx=0 local p
for p in "$@"; do case $mode in preprocess) files[$idx]=$p idx=$idx+1 ;; totals) t_files[$idx]=$p idx=$idx+1 ;; slabs) files[$idx]=$p idx=$idx+1 ;; esac done}
parse_opts "$@"argstart=$?parse_args "${@:$argstart}"
if [ ${#files[@]} -eq 0 ] && [ ${#t_files[@]} -eq 0 ]; then usage exit 1fi
case $mode in preprocess) for i in "${files[@]}"; do do_preprocess "$i" done ;; totals) do_totals_plotting ;; slabs) for i in "${files[@]}"; do do_slabs_plotting "$i" done ;; *) echo "Unknown mode $mode" >&2 usage exit 1 ;;esac