1*4882a593Smuzhiyun#!/usr/bin/env bash 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# Copyright (c) 2011, Intel Corporation. 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-or-later 6*4882a593Smuzhiyun# 7*4882a593Smuzhiyun# DESCRIPTION 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun# Produces script data to be consumed by gnuplot. There are two possible plots 10*4882a593Smuzhiyun# depending if either the -S parameter is present or not: 11*4882a593Smuzhiyun# 12*4882a593Smuzhiyun# * without -S: Produces a histogram listing top N recipes/tasks versus 13*4882a593Smuzhiyun# stats. The first stat defined in the -s parameter is the one taken 14*4882a593Smuzhiyun# into account for ranking 15*4882a593Smuzhiyun# * -S: Produces a histogram listing tasks versus stats. In this case, 16*4882a593Smuzhiyun# the value of each stat is the sum for that particular stat in all recipes found. 17*4882a593Smuzhiyun# Stats values are in descending order defined by the first stat defined on -s 18*4882a593Smuzhiyun# 19*4882a593Smuzhiyun# EXAMPLES 20*4882a593Smuzhiyun# 21*4882a593Smuzhiyun# 1. Top recipes' tasks taking into account utime 22*4882a593Smuzhiyun# 23*4882a593Smuzhiyun# $ buildstats-plot.sh -s utime | gnuplot -p 24*4882a593Smuzhiyun# 25*4882a593Smuzhiyun# 2. Tasks versus utime:stime 26*4882a593Smuzhiyun# 27*4882a593Smuzhiyun# $ buildstats-plot.sh -s utime:stime -S | gnuplot -p 28*4882a593Smuzhiyun# 29*4882a593Smuzhiyun# 3. Tasks versus IO write_bytes:IO read_bytes 30*4882a593Smuzhiyun# 31*4882a593Smuzhiyun# $ buildstats-plot.sh -s 'IO write_bytes:IO read_bytes' -S | gnuplot -p 32*4882a593Smuzhiyun# 33*4882a593Smuzhiyun# AUTHORS 34*4882a593Smuzhiyun# Leonardo Sandoval <leonardo.sandoval.gonzalez@linux.intel.com> 35*4882a593Smuzhiyun# 36*4882a593Smuzhiyun 37*4882a593Smuzhiyunset -o nounset 38*4882a593Smuzhiyunset -o errexit 39*4882a593Smuzhiyun 40*4882a593SmuzhiyunBS_DIR="tmp/buildstats" 41*4882a593SmuzhiyunN=10 42*4882a593SmuzhiyunRECIPE="" 43*4882a593SmuzhiyunTASKS="compile:configure:fetch:install:patch:populate_lic:populate_sysroot:unpack" 44*4882a593SmuzhiyunSTATS="utime" 45*4882a593SmuzhiyunACCUMULATE="" 46*4882a593SmuzhiyunSUM="" 47*4882a593SmuzhiyunOUTDATA_FILE="$PWD/buildstats-plot.out" 48*4882a593Smuzhiyun 49*4882a593Smuzhiyunfunction usage { 50*4882a593Smuzhiyun CMD=$(basename $0) 51*4882a593Smuzhiyun cat <<EOM 52*4882a593SmuzhiyunUsage: $CMD [-b buildstats_dir] [-t do_task] 53*4882a593Smuzhiyun -b buildstats The path where the folder resides 54*4882a593Smuzhiyun (default: "$BS_DIR") 55*4882a593Smuzhiyun -n N Top N recipes to display. Ignored if -S is present 56*4882a593Smuzhiyun (default: "$N") 57*4882a593Smuzhiyun -r recipe The recipe mask to be searched 58*4882a593Smuzhiyun -t tasks The tasks to be computed 59*4882a593Smuzhiyun (default: "$TASKS") 60*4882a593Smuzhiyun -s stats The stats to be matched. If more that one stat, units 61*4882a593Smuzhiyun should be the same because data is plot as histogram. 62*4882a593Smuzhiyun (see buildstats.sh -h for all options) or any other defined 63*4882a593Smuzhiyun (build)stat separated by colons, i.e. stime:utime 64*4882a593Smuzhiyun (default: "$STATS") 65*4882a593Smuzhiyun -a Accumulate all stats values for found recipes 66*4882a593Smuzhiyun -S Sum values for a particular stat for found recipes 67*4882a593Smuzhiyun -o Output data file. 68*4882a593Smuzhiyun (default: "$OUTDATA_FILE") 69*4882a593Smuzhiyun -h Display this help message 70*4882a593SmuzhiyunEOM 71*4882a593Smuzhiyun} 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun# Parse and validate arguments 74*4882a593Smuzhiyunwhile getopts "b:n:r:t:s:o:aSh" OPT; do 75*4882a593Smuzhiyun case $OPT in 76*4882a593Smuzhiyun b) 77*4882a593Smuzhiyun BS_DIR="$OPTARG" 78*4882a593Smuzhiyun ;; 79*4882a593Smuzhiyun n) 80*4882a593Smuzhiyun N="$OPTARG" 81*4882a593Smuzhiyun ;; 82*4882a593Smuzhiyun r) 83*4882a593Smuzhiyun RECIPE="-r $OPTARG" 84*4882a593Smuzhiyun ;; 85*4882a593Smuzhiyun t) 86*4882a593Smuzhiyun TASKS="$OPTARG" 87*4882a593Smuzhiyun ;; 88*4882a593Smuzhiyun s) 89*4882a593Smuzhiyun STATS="$OPTARG" 90*4882a593Smuzhiyun ;; 91*4882a593Smuzhiyun a) 92*4882a593Smuzhiyun ACCUMULATE="-a" 93*4882a593Smuzhiyun ;; 94*4882a593Smuzhiyun S) 95*4882a593Smuzhiyun SUM="y" 96*4882a593Smuzhiyun ;; 97*4882a593Smuzhiyun o) 98*4882a593Smuzhiyun OUTDATA_FILE="$OPTARG" 99*4882a593Smuzhiyun ;; 100*4882a593Smuzhiyun h) 101*4882a593Smuzhiyun usage 102*4882a593Smuzhiyun exit 0 103*4882a593Smuzhiyun ;; 104*4882a593Smuzhiyun *) 105*4882a593Smuzhiyun usage 106*4882a593Smuzhiyun exit 1 107*4882a593Smuzhiyun ;; 108*4882a593Smuzhiyun esac 109*4882a593Smuzhiyundone 110*4882a593Smuzhiyun 111*4882a593Smuzhiyun# Get number of stats 112*4882a593SmuzhiyunIFS=':'; statsarray=(${STATS}); unset IFS 113*4882a593Smuzhiyunnstats=${#statsarray[@]} 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun# Get script folder, use to run buildstats.sh 116*4882a593SmuzhiyunCD=$(dirname $0) 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun# Parse buildstats recipes to produce a single table 119*4882a593SmuzhiyunOUTBUILDSTATS="$PWD/buildstats.log" 120*4882a593Smuzhiyun$CD/buildstats.sh -b "$BS_DIR" -s "$STATS" -t "$TASKS" $RECIPE $ACCUMULATE -H > $OUTBUILDSTATS 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun# Get headers 123*4882a593SmuzhiyunHEADERS=$(cat $OUTBUILDSTATS | sed -n -e 's/\(.*\)/"\1"/' -e '1s/ /\\\\\\\\ /g' -e 's/_/\\\\\\\\_/g' -e '1s/:/" "/gp') 124*4882a593Smuzhiyun 125*4882a593Smuzhiyunecho -e "set boxwidth 0.9 relative" 126*4882a593Smuzhiyunecho -e "set style data histograms" 127*4882a593Smuzhiyunecho -e "set style fill solid 1.0 border lt -1" 128*4882a593Smuzhiyunecho -e "set xtics rotate by 45 right" 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun# Get output data 131*4882a593Smuzhiyunif [ -z "$SUM" ]; then 132*4882a593Smuzhiyun cat $OUTBUILDSTATS | sed -e '1d' -e 's/_/\\\\_/g' | sort -k3 -n -r | head -$N > $OUTDATA_FILE 133*4882a593Smuzhiyun # include task at recipe column 134*4882a593Smuzhiyun sed -i -e "1i\ 135*4882a593Smuzhiyun${HEADERS}" $OUTDATA_FILE 136*4882a593Smuzhiyun echo -e "set title \"Top task/recipes\"" 137*4882a593Smuzhiyun echo -e "plot for [COL=3:`expr 3 + ${nstats} - 1`] '${OUTDATA_FILE}' using COL:xtic(stringcolumn(1).' '.stringcolumn(2)) title columnheader(COL)" 138*4882a593Smuzhiyunelse 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun # Construct datatamash sum argument (sum 3 sum 4 ...) 141*4882a593Smuzhiyun declare -a sumargs 142*4882a593Smuzhiyun j=0 143*4882a593Smuzhiyun for i in `seq $nstats`; do 144*4882a593Smuzhiyun sumargs[j]=sum; j=$(( $j + 1 )) 145*4882a593Smuzhiyun sumargs[j]=`expr 3 + $i - 1`; j=$(( $j + 1 )) 146*4882a593Smuzhiyun done 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun # Do the processing with datamash 149*4882a593Smuzhiyun cat $OUTBUILDSTATS | sed -e '1d' | datamash -t ' ' -g1 ${sumargs[*]} | sort -k2 -n -r > $OUTDATA_FILE 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun # Include headers into resulted file, so we can include gnuplot xtics 152*4882a593Smuzhiyun HEADERS=$(echo $HEADERS | sed -e 's/recipe//1') 153*4882a593Smuzhiyun sed -i -e "1i\ 154*4882a593Smuzhiyun${HEADERS}" $OUTDATA_FILE 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun # Plot 157*4882a593Smuzhiyun echo -e "set title \"Sum stats values per task for all recipes\"" 158*4882a593Smuzhiyun echo -e "plot for [COL=2:`expr 2 + ${nstats} - 1`] '${OUTDATA_FILE}' using COL:xtic(1) title columnheader(COL)" 159*4882a593Smuzhiyunfi 160*4882a593Smuzhiyun 161