1#!/bin/bash 2 3# Build performance regression test script 4# 5# Copyright 2011 Intel Corporation 6# 7# SPDX-License-Identifier: GPL-2.0-or-later 8# 9# DESCRIPTION 10# This script is intended to be used in conjunction with "git bisect run" 11# in order to find regressions in build time, however it can also be used 12# independently. It cleans out the build output directories, runs a 13# specified worker script (an example is test_build_time_worker.sh) under 14# TIME(1), logs the results to TEST_LOGDIR (default /tmp) and returns a 15# value telling "git bisect run" whether the build time is good (under 16# the specified threshold) or bad (over it). There is also a tolerance 17# option but it is not particularly useful as it only subtracts the 18# tolerance from the given threshold and uses it as the actual threshold. 19# 20# It is also capable of taking a file listing git revision hashes to be 21# test-applied to the repository in order to get past build failures that 22# would otherwise cause certain revisions to have to be skipped; if a 23# revision does not apply cleanly then the script assumes it does not 24# need to be applied and ignores it. 25# 26# Please see the help output (syntax below) for some important setup 27# instructions. 28# 29# AUTHORS 30# Paul Eggleton <paul.eggleton@linux.intel.com> 31 32 33syntax() { 34 echo "syntax: $0 <script> <time> <tolerance> [patchrevlist]" 35 echo "" 36 echo " script - worker script file (if in current dir, prefix with ./)" 37 echo " time - time threshold (in seconds, suffix m for minutes)" 38 echo " tolerance - tolerance (in seconds, suffix m for minutes or % for" 39 echo " percentage, can be 0)" 40 echo " patchrevlist - optional file listing revisions to apply as patches on top" 41 echo "" 42 echo "You must set TEST_BUILDDIR to point to a previously created build directory," 43 echo "however please note that this script will wipe out the TMPDIR defined in" 44 echo "TEST_BUILDDIR/conf/local.conf as part of its initial setup (as well as your" 45 echo "~/.ccache)" 46 echo "" 47 echo "To get rid of the sudo prompt, please add the following line to /etc/sudoers" 48 echo "(use 'visudo' to edit this; also it is assumed that the user you are running" 49 echo "as is a member of the 'wheel' group):" 50 echo "" 51 echo "%wheel ALL=(ALL) NOPASSWD: /sbin/sysctl -w vm.drop_caches=[1-3]" 52 echo "" 53 echo "Note: it is recommended that you disable crond and any other process that" 54 echo "may cause significant CPU or I/O usage during build performance tests." 55} 56 57# Note - we exit with 250 here because that will tell git bisect run that 58# something bad happened and stop 59if [ "$1" = "" ] ; then 60 syntax 61 exit 250 62fi 63 64if [ "$2" = "" ] ; then 65 syntax 66 exit 250 67fi 68 69if [ "$3" = "" ] ; then 70 syntax 71 exit 250 72fi 73 74if ! [[ "$2" =~ ^[0-9][0-9m.]*$ ]] ; then 75 echo "'$2' is not a valid number for threshold" 76 exit 250 77fi 78 79if ! [[ "$3" =~ ^[0-9][0-9m.%]*$ ]] ; then 80 echo "'$3' is not a valid number for tolerance" 81 exit 250 82fi 83 84if [ "$TEST_BUILDDIR" = "" ] ; then 85 echo "Please set TEST_BUILDDIR to a previously created build directory" 86 exit 250 87fi 88 89if [ ! -d "$TEST_BUILDDIR" ] ; then 90 echo "TEST_BUILDDIR $TEST_BUILDDIR not found" 91 exit 250 92fi 93 94git diff --quiet 95if [ $? != 0 ] ; then 96 echo "Working tree is dirty, cannot proceed" 97 exit 251 98fi 99 100if [ "BB_ENV_PASSTHROUGH_ADDITIONS" != "" ] ; then 101 echo "WARNING: you are running after sourcing the build environment script, this is not recommended" 102fi 103 104runscript=$1 105timethreshold=$2 106tolerance=$3 107 108if [ "$4" != "" ] ; then 109 patchrevlist=`cat $4` 110else 111 patchrevlist="" 112fi 113 114if [[ timethreshold == *m* ]] ; then 115 timethreshold=`echo $timethreshold | sed s/m/*60/ | bc` 116fi 117 118if [[ $tolerance == *m* ]] ; then 119 tolerance=`echo $tolerance | sed s/m/*60/ | bc` 120elif [[ $tolerance == *%* ]] ; then 121 tolerance=`echo $tolerance | sed s/%//` 122 tolerance=`echo "scale = 2; (($tolerance * $timethreshold) / 100)" | bc` 123fi 124 125tmpdir=`grep "^TMPDIR" $TEST_BUILDDIR/conf/local.conf | sed -e 's/TMPDIR[ \t]*=[ \t\?]*"//' -e 's/"//'` 126if [ "x$tmpdir" = "x" ]; then 127 echo "Unable to determine TMPDIR from $TEST_BUILDDIR/conf/local.conf, bailing out" 128 exit 250 129fi 130sstatedir=`grep "^SSTATE_DIR" $TEST_BUILDDIR/conf/local.conf | sed -e 's/SSTATE_DIR[ \t\?]*=[ \t]*"//' -e 's/"//'` 131if [ "x$sstatedir" = "x" ]; then 132 echo "Unable to determine SSTATE_DIR from $TEST_BUILDDIR/conf/local.conf, bailing out" 133 exit 250 134fi 135 136if [ `expr length $tmpdir` -lt 4 ] ; then 137 echo "TMPDIR $tmpdir is less than 4 characters, bailing out" 138 exit 250 139fi 140 141if [ `expr length $sstatedir` -lt 4 ] ; then 142 echo "SSTATE_DIR $sstatedir is less than 4 characters, bailing out" 143 exit 250 144fi 145 146echo -n "About to wipe out TMPDIR $tmpdir, press Ctrl+C to break out... " 147for i in 9 8 7 6 5 4 3 2 1 148do 149 echo -ne "\x08$i" 150 sleep 1 151done 152echo 153 154pushd . > /dev/null 155 156rm -f pseudodone 157echo "Removing TMPDIR $tmpdir..." 158rm -rf $tmpdir 159echo "Removing TMPDIR $tmpdir-*libc..." 160rm -rf $tmpdir-*libc 161echo "Removing SSTATE_DIR $sstatedir..." 162rm -rf $sstatedir 163echo "Removing ~/.ccache..." 164rm -rf ~/.ccache 165 166echo "Syncing..." 167sync 168sync 169echo "Dropping VM cache..." 170#echo 3 > /proc/sys/vm/drop_caches 171sudo /sbin/sysctl -w vm.drop_caches=3 > /dev/null 172 173if [ "$TEST_LOGDIR" = "" ] ; then 174 logdir="/tmp" 175else 176 logdir="$TEST_LOGDIR" 177fi 178rev=`git rev-parse HEAD` 179logfile="$logdir/timelog_$rev.log" 180echo -n > $logfile 181 182gitroot=`git rev-parse --show-toplevel` 183cd $gitroot 184for patchrev in $patchrevlist ; do 185 echo "Applying $patchrev" 186 patchfile=`mktemp` 187 git show $patchrev > $patchfile 188 git apply --check $patchfile &> /dev/null 189 if [ $? != 0 ] ; then 190 echo " ... patch does not apply without errors, ignoring" 191 else 192 echo "Applied $patchrev" >> $logfile 193 git apply $patchfile &> /dev/null 194 fi 195 rm $patchfile 196done 197 198sync 199echo "Quiescing for 5s..." 200sleep 5 201 202echo "Running $runscript at $rev..." 203timeoutfile=`mktemp` 204/usr/bin/time -o $timeoutfile -f "%e\nreal\t%E\nuser\t%Us\nsys\t%Ss\nmaxm\t%Mk" $runscript 2>&1 | tee -a $logfile 205exitstatus=$PIPESTATUS 206 207git reset --hard HEAD > /dev/null 208popd > /dev/null 209 210timeresult=`head -n1 $timeoutfile` 211cat $timeoutfile | tee -a $logfile 212rm $timeoutfile 213 214if [ $exitstatus != 0 ] ; then 215 # Build failed, exit with 125 to tell git bisect run to skip this rev 216 echo "*** Build failed (exit code $exitstatus), skipping..." | tee -a $logfile 217 exit 125 218fi 219 220ret=`echo "scale = 2; $timeresult > $timethreshold - $tolerance" | bc` 221echo "Returning $ret" | tee -a $logfile 222exit $ret 223 224