1#!/bin/bash 2# 3# Copyright (c) 2011, Intel Corporation. 4# 5# SPDX-License-Identifier: GPL-2.0-or-later 6# 7# DESCRIPTION 8# Given 'buildstats' data (generate by bitbake when setting 9# USER_CLASSES ?= "buildstats" on local.conf), task names and a stats values 10# (these are the ones preset on the buildstats files), outputs 11# '<task> <recipe> <value_1> <value_2> ... <value_n>'. The units are the ones 12# defined at buildstats, which in turn takes data from /proc/[pid] files 13# 14# Some useful pipelines 15# 16# 1. Tasks with largest stime (Amount of time that this process has been scheduled 17# in kernel mode) values 18# $ buildstats.sh -b <buildstats> -s stime | sort -k3 -n -r | head 19# 20# 2. Min, max, sum utime (Amount of time that this process has been scheduled 21# in user mode) per task (in needs GNU datamash) 22# $ buildstats.sh -b <buildstats> -s utime | datamash -t' ' -g1 min 3 max 3 sum 3 | sort -k4 -n -r 23# 24# AUTHORS 25# Leonardo Sandoval <leonardo.sandoval.gonzalez@linux.intel.com> 26# 27 28# Stats, by type 29TIME="utime:stime:cutime:cstime" 30IO="IO wchar:IO write_bytes:IO syscr:IO read_bytes:IO rchar:IO syscw:IO cancelled_write_bytes" 31RUSAGE="rusage ru_utime:rusage ru_stime:rusage ru_maxrss:rusage ru_minflt:rusage ru_majflt:\ 32rusage ru_inblock:rusage ru_oublock:rusage ru_nvcsw:rusage ru_nivcsw" 33 34CHILD_RUSAGE="Child rusage ru_utime:Child rusage ru_stime:Child rusage ru_maxrss:Child rusage ru_minflt:\ 35Child rusage ru_majflt:Child rusage ru_inblock:Child rusage ru_oublock:Child rusage ru_nvcsw:\ 36Child rusage ru_nivcsw" 37 38BS_DIR="tmp/buildstats" 39RECIPE="" 40TASKS="compile:configure:fetch:install:patch:populate_lic:populate_sysroot:unpack" 41STATS="$TIME" 42ACCUMULATE="" 43HEADER="" # No header by default 44 45function usage { 46CMD=$(basename $0) 47cat <<EOM 48Usage: $CMD [-b buildstats_dir] [-t do_task] 49 -b buildstats The path where the folder resides 50 (default: "$BS_DIR") 51 -r recipe The recipe to be computed 52 -t tasks The tasks to be computed 53 (default: "$TASKS") 54 -s stats The stats to be matched. Options: TIME, IO, RUSAGE, CHILD_RUSAGE 55 or any other defined buildstat separated by colons, i.e. stime:utime 56 (default: "$STATS") 57 Default stat sets: 58 TIME=$TIME 59 IO=$IO 60 RUSAGE=$RUSAGE 61 CHILD_RUSAGE=$CHILD_RUSAGE 62 -a Accumulate all stats values for found recipes 63 -h Display this help message 64EOM 65} 66 67# Parse and validate arguments 68while getopts "b:r:t:s:aHh" OPT; do 69 case $OPT in 70 b) 71 BS_DIR="$OPTARG" 72 ;; 73 r) 74 RECIPE="$OPTARG" 75 ;; 76 t) 77 TASKS="$OPTARG" 78 ;; 79 s) 80 STATS="$OPTARG" 81 ;; 82 a) 83 ACCUMULATE="y" 84 ;; 85 H) 86 HEADER="y" 87 ;; 88 h) 89 usage 90 exit 0 91 ;; 92 *) 93 usage 94 exit 1 95 ;; 96 esac 97done 98 99# Ensure the buildstats folder exists 100if [ ! -d "$BS_DIR" ]; then 101 echo "ERROR: $BS_DIR does not exist" 102 usage 103 exit 1 104fi 105 106stats="" 107IFS=":" 108for stat in ${STATS}; do 109 case $stat in 110 TIME) 111 stats="${stats}:${TIME}" 112 ;; 113 IO) 114 stats="${stats}:${IO}" 115 ;; 116 RUSAGE) 117 stats="${stats}:${RUSAGE}" 118 ;; 119 CHILD_RUSAGE) 120 stats="${stats}:${CHILD_RUSAGE}" 121 ;; 122 *) 123 stats="${STATS}" 124 ;; 125 esac 126done 127 128# remove possible colon at the beginning 129stats="$(echo "$stats" | sed -e 's/^://1')" 130 131# Provide a header if required by the user 132if [ -n "$HEADER" ] ; then 133 if [ -n "$ACCUMULATE" ]; then 134 echo "task:recipe:accumulated(${stats//:/;})" 135 else 136 echo "task:recipe:$stats" 137 fi 138fi 139 140for task in ${TASKS}; do 141 task="do_${task}" 142 for file in $(find ${BS_DIR} -type f -path *${RECIPE}*/${task} | awk 'BEGIN{ ORS=""; OFS=":" } { print $0,"" }'); do 143 recipe="$(basename $(dirname $file))" 144 times="" 145 for stat in ${stats}; do 146 [ -z "$stat" ] && { echo "empty stats"; } 147 time=$(sed -n -e "s/^\($stat\): \\(.*\\)/\\2/p" $file) 148 # in case the stat is not present, set the value as NA 149 [ -z "$time" ] && { time="NA"; } 150 # Append it to times 151 if [ -z "$times" ]; then 152 times="${time}" 153 else 154 times="${times} ${time}" 155 fi 156 done 157 if [ -n "$ACCUMULATE" ]; then 158 IFS=' '; valuesarray=(${times}); IFS=':' 159 times=0 160 for value in "${valuesarray[@]}"; do 161 [ "$value" == "NA" ] && { echo "ERROR: stat is not present."; usage; exit 1; } 162 times=$(( $times + $value )) 163 done 164 fi 165 echo "${task} ${recipe} ${times}" 166 done 167done 168