summaryrefslogtreecommitdiffstats
path: root/scripts/contrib/test_build_time.sh
blob: 23f238adf6e0ae45f6f489a3b7a20d2d0e4cc8d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/bin/bash

# Build performance regression test script
#
# Copyright 2011 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# DESCRIPTION
# This script is intended to be used in conjunction with "git bisect run"
# in order to find regressions in build time, however it can also be used
# independently. It cleans out the build output directories, runs a
# specified worker script (an example is test_build_time_worker.sh) under
# TIME(1), logs the results to TEST_LOGDIR (default /tmp) and returns a
# value telling "git bisect run" whether the build time is good (under
# the specified threshold) or bad (over it). There is also a tolerance
# option but it is not particularly useful as it only subtracts the
# tolerance from the given threshold and uses it as the actual threshold.
#
# It is also capable of taking a file listing git revision hashes to be
# test-applied to the repository in order to get past build failures that
# would otherwise cause certain revisions to have to be skipped; if a
# revision does not apply cleanly then the script assumes it does not
# need to be applied and ignores it.
#
# Please see the help output (syntax below) for some important setup
# instructions.
#
# AUTHORS
# Paul Eggleton <paul.eggleton@linux.intel.com>


syntax() {
    echo "syntax: $0 <script> <time> <tolerance> [patchrevlist]"
    echo ""
    echo "  script       - worker script file (if in current dir, prefix with ./)"
    echo "  time         - time threshold (in seconds, suffix m for minutes)"
    echo "  tolerance    - tolerance (in seconds, suffix m for minutes or % for"
    echo "                 percentage, can be 0)"
    echo "  patchrevlist - optional file listing revisions to apply as patches on top"
    echo ""
    echo "You must set TEST_BUILDDIR to point to a previously created build directory,"
    echo "however please note that this script will wipe out the TMPDIR defined in"
    echo "TEST_BUILDDIR/conf/local.conf as part of its initial setup (as well as your"
    echo "~/.ccache)"
    echo ""
    echo "To get rid of the sudo prompt, please add the following line to /etc/sudoers"
    echo "(use 'visudo' to edit this; also it is assumed that the user you are running"
    echo "as is a member of the 'wheel' group):"
    echo ""
    echo "%wheel ALL=(ALL) NOPASSWD: /sbin/sysctl -w vm.drop_caches=[1-3]"
    echo ""
    echo "Note: it is recommended that you disable crond and any other process that"
    echo "may cause significant CPU or I/O usage during build performance tests."
}

# Note - we exit with 250 here because that will tell git bisect run that
# something bad happened and stop
if [ "$1" = "" ] ; then
   syntax
   exit 250
fi

if [ "$2" = "" ] ; then
   syntax
   exit 250
fi

if [ "$3" = "" ] ; then
   syntax
   exit 250
fi

if ! [[ "$2" =~ ^[0-9][0-9m.]*$ ]] ; then
   echo "'$2' is not a valid number for threshold"
   exit 250
fi

if ! [[ "$3" =~ ^[0-9][0-9m.%]*$ ]] ; then
   echo "'$3' is not a valid number for tolerance"
   exit 250
fi

if [ "$TEST_BUILDDIR" = "" ] ; then
   echo "Please set TEST_BUILDDIR to a previously created build directory"
   exit 250
fi

if [ ! -d "$TEST_BUILDDIR" ] ; then
   echo "TEST_BUILDDIR $TEST_BUILDDIR not found"
   exit 250
fi

git diff --quiet
if [ $? != 0 ] ; then
    echo "Working tree is dirty, cannot proceed"
    exit 251
fi

if [ "$BB_ENV_EXTRAWHITE" != "" ] ; then
   echo "WARNING: you are running after sourcing the build environment script, this is not recommended"
fi

runscript=$1
timethreshold=$2
tolerance=$3

if [ "$4" != "" ] ; then
    patchrevlist=`cat $4`
else
    patchrevlist=""
fi

if [[ timethreshold == *m* ]] ; then
    timethreshold=`echo $timethreshold | sed s/m/*60/ | bc`
fi

if [[ $tolerance == *m* ]] ; then
    tolerance=`echo $tolerance | sed s/m/*60/ | bc`
elif [[ $tolerance == *%* ]] ; then
    tolerance=`echo $tolerance | sed s/%//`
    tolerance=`echo "scale = 2; (($tolerance * $timethreshold) / 100)" | bc`
fi

tmpdir=`grep "^TMPDIR" $TEST_BUILDDIR/conf/local.conf | sed -e 's/TMPDIR[ \t]*=[ \t\?]*"//' -e 's/"//'`
if [ "x$tmpdir" = "x" ]; then
    echo "Unable to determine TMPDIR from $TEST_BUILDDIR/conf/local.conf, bailing out"
    exit 250
fi
sstatedir=`grep "^SSTATE_DIR" $TEST_BUILDDIR/conf/local.conf | sed -e 's/SSTATE_DIR[ \t\?]*=[ \t]*"//' -e 's/"//'`
if [ "x$sstatedir" = "x" ]; then
    echo "Unable to determine SSTATE_DIR from $TEST_BUILDDIR/conf/local.conf, bailing out"
    exit 250
fi

if [ `expr length $tmpdir` -lt 4 ] ; then
    echo "TMPDIR $tmpdir is less than 4 characters, bailing out"
    exit 250
fi

if [ `expr length $sstatedir` -lt 4 ] ; then
    echo "SSTATE_DIR $sstatedir is less than 4 characters, bailing out"
    exit 250
fi

echo -n "About to wipe out TMPDIR $tmpdir, press Ctrl+C to break out...  "
for i in 9 8 7 6 5 4 3 2 1
do
    echo -ne "\x08$i"
    sleep 1
done
echo

pushd . > /dev/null

rm -f pseudodone
echo "Removing TMPDIR $tmpdir..."
rm -rf $tmpdir
echo "Removing TMPDIR $tmpdir-*libc..."
rm -rf $tmpdir-*libc
echo "Removing SSTATE_DIR $sstatedir..."
rm -rf $sstatedir
echo "Removing ~/.ccache..."
rm -rf ~/.ccache

echo "Syncing..."
sync
sync
echo "Dropping VM cache..."
#echo 3 > /proc/sys/vm/drop_caches
sudo /sbin/sysctl -w vm.drop_caches=3 > /dev/null

if [ "$TEST_LOGDIR" = "" ] ; then
    logdir="/tmp"
else
    logdir="$TEST_LOGDIR"
fi
rev=`git rev-parse HEAD`
logfile="$logdir/timelog_$rev.log"
echo -n > $logfile

gitroot=`git rev-parse --show-toplevel`
cd $gitroot
for patchrev in $patchrevlist ; do
    echo "Applying $patchrev"
    patchfile=`mktemp`
    git show $patchrev > $patchfile
    git apply --check $patchfile &> /dev/null
    if [ $? != 0 ] ; then
        echo " ... patch does not apply without errors, ignoring"
    else
        echo "Applied $patchrev" >> $logfile
        git apply $patchfile &> /dev/null
    fi
    rm $patchfile
done

sync
echo "Quiescing for 5s..."
sleep 5

echo "Running $runscript at $rev..."
timeoutfile=`mktemp`
/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
exitstatus=$PIPESTATUS

git reset --hard HEAD > /dev/null
popd > /dev/null

timeresult=`head -n1 $timeoutfile`
cat $timeoutfile | tee -a $logfile
rm $timeoutfile

if [ $exitstatus != 0 ] ; then
    # Build failed, exit with 125 to tell git bisect run to skip this rev
    echo "*** Build failed (exit code $exitstatus), skipping..." | tee -a $logfile
    exit 125
fi

ret=`echo "scale = 2; $timeresult > $timethreshold - $tolerance" | bc`
echo "Returning $ret" | tee -a $logfile
exit $ret