aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8.1/contrib/patch_tester.sh
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8.1/contrib/patch_tester.sh')
-rwxr-xr-xgcc-4.8.1/contrib/patch_tester.sh518
1 files changed, 518 insertions, 0 deletions
diff --git a/gcc-4.8.1/contrib/patch_tester.sh b/gcc-4.8.1/contrib/patch_tester.sh
new file mode 100755
index 000000000..74b8e9e8c
--- /dev/null
+++ b/gcc-4.8.1/contrib/patch_tester.sh
@@ -0,0 +1,518 @@
+#!/bin/sh
+
+# Tests a set of patches from a directory.
+# Copyright (C) 2007, 2008, 2011 Free Software Foundation, Inc.
+# Contributed by Sebastian Pop <sebastian.pop@amd.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+cat <<EOF
+
+WARNING: This script should only be fed with patches from known
+ authorized and trusted sources. Don't even think about
+ hooking it up to a raw feed from the gcc-patches list or
+ you'll regret it.
+
+EOF
+
+args=$@
+
+svnpath=svn://gcc.gnu.org/svn/gcc
+dashj=
+default_standby=1
+standby=$default_standby
+default_watermark=0.60
+watermark=$default_watermark
+savecompilers=false
+nopristinecache=false
+nogpg=false
+stop=false
+
+usage() {
+ cat <<EOF
+patch_tester.sh [-j<N>] [-standby N] [-watermark N] [-savecompilers] [-nogpg]
+ [-svnpath URL] [-stop] [-nopristinecache]
+ <source_dir> [patches_dir [state_dir [build_dir]]]
+
+ J is the flag passed to make. Default is empty string.
+
+ STANDBY is the number of minutes between checks for new patches in
+ PATCHES_DIR. Default is ${default_standby} minutes.
+
+ WATERMARK is the 5 minute average system charge under which a new
+ compile can start. Default is ${default_watermark}.
+
+ SAVECOMPILERS copies the compilers in the same directory as the
+ test results for the non patched version. Default is not copy.
+
+ NOPRISTINECACHE prevents use of cached test results from any earlier
+ test runs on the pristine version of the branch and revision under
+ test (the default behaviour). This should be used when testing the
+ same revision and patch with multiple sets of configure options, as
+ these may affect the set of baseline failures.
+
+ NOGPG can be used to avoid checking the GPG signature of patches.
+
+ URL is the location of the GCC SVN repository. The default is
+ ${svnpath}.
+
+ STOP exits when PATCHES_DIR is empty.
+
+ SOURCE_DIR is the directory containing GCC's toplevel configure.
+
+ PATCHES_DIR is the directory containing the patches to be tested.
+ Default is SOURCE_DIR/patches.
+
+ STATE_DIR is where the tester maintains its internal state.
+ Default is SOURCE_DIR/state.
+
+ BUILD_DIR is the build tree, a temporary directory that this
+ script will delete and recreate. Default is SOURCE_DIR/obj.
+
+EOF
+ exit 1
+}
+
+makedir () {
+ DIRNAME=$1
+ mkdir -p $DIRNAME
+ if [ $? -ne 0 ]; then
+ echo "ERROR: could not make directory $DIRNAME"
+ exit 1
+ fi
+}
+
+while [ $# -ne 0 ]; do
+ case $1 in
+ -j*)
+ dashj=$1; shift
+ ;;
+ -standby)
+ [[ $# > 2 ]] || usage
+ standby=$2; shift; shift
+ ;;
+ -watermark)
+ [[ $# > 2 ]] || usage
+ watermark=$2; shift; shift
+ ;;
+ -savecompilers)
+ savecompilers=true; shift
+ ;;
+ -nopristinecache)
+ nopristinecache=true; shift
+ ;;
+ -nogpg)
+ nogpg=true; shift
+ ;;
+ -stop)
+ stop=true; shift
+ ;;
+ -svnpath)
+ svnpath=$2; shift; shift
+ ;;
+ -*)
+ echo "Invalid option: $1"
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+test $# -eq 0 && usage
+
+SOURCE=$1
+PATCHES=
+STATE=
+BUILD=
+
+if [[ $# < 2 ]]; then
+ PATCHES=$SOURCE/patches
+else
+ PATCHES=$2
+fi
+if [[ $# < 3 ]]; then
+ STATE=$SOURCE/state
+else
+ STATE=$3
+fi
+if [[ $# < 4 ]]; then
+ BUILD=$SOURCE/obj
+else
+ BUILD=$4
+fi
+
+[ -d $PATCHES ] || makedir $PATCHES
+[ -d $STATE ] || makedir $STATE
+[ -d $STATE/patched ] || makedir $STATE/patched
+[ -d $SOURCE ] || makedir $SOURCE
+[ -f $SOURCE/config.guess ] || {
+ cd $SOURCE
+ svn -q co $svnpath/trunk .
+ if [ $? -ne 0 ]; then
+ echo "ERROR: initial svn checkout failed"
+ exit 1
+ fi
+}
+
+# This can contain required local settings:
+# default_config configure options, always passed
+# default_make make bootstrap options, always passed
+# default_check make check options, always passed
+[ -f $STATE/defaults ] && . $STATE/defaults
+
+VERSION=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
+
+exec >> $STATE/tester.log 2>&1 || exit 1
+set -x
+
+TESTING=$STATE/testing
+REPORT=$TESTING/report
+PRISTINE=$TESTING/pristine
+PATCHED=$TESTING/patched
+PATCH=
+TARGET=`$SOURCE/config.guess || exit 1`
+TESTLOGS="gcc/testsuite/gcc/gcc.sum
+gcc/testsuite/gfortran/gfortran.sum
+gcc/testsuite/g++/g++.sum
+gcc/testsuite/objc/objc.sum
+$TARGET/libstdc++-v3/testsuite/libstdc++.sum
+$TARGET/libffi/testsuite/libffi.sum
+$TARGET/libjava/testsuite/libjava.sum
+$TARGET/libgomp/testsuite/libgomp.sum
+$TARGET/libmudflap/testsuite/libmudflap.sum"
+COMPILERS="gcc/cc1
+gcc/cc1obj
+gcc/cc1plus
+gcc/f951
+gcc/jc1
+gcc/gnat1
+gcc/tree1"
+
+now () {
+ echo `TZ=UTC date +"%Y_%m_%d_%H_%M_%S"`
+}
+
+report () {
+ echo "$@" >> $REPORT
+}
+
+freport () {
+ if [ -s $1 ]; then
+ report "(cat $1"
+ cat $1 >> $REPORT
+ report "tac)"
+ fi
+}
+
+cleanup () {
+ cd $SOURCE
+ svn cleanup && svn revert -R . && svn st | cut -d' ' -f5- | xargs rm -v
+}
+
+selfexec () {
+ exec ${CONFIG_SHELL-/bin/sh} $0 $args
+}
+
+update () {
+ svn_branch=`grep "^branch:" $PATCH | sed -e "s/^branch://g" -e "s/ //g"`
+ if [ x$svn_branch = x ]; then
+ svn_branch=trunk
+ fi
+
+ svn_revision=`grep "^revision:" $PATCH | sed -e "s/^revision://g" -e "s/ //g"`
+ if [ x$svn_revision = x ]; then
+ svn_revision=HEAD
+ fi
+
+ cleanup
+ cd $SOURCE
+ case $svn_branch in
+ trunk)
+ if ! svn switch -r $svn_revision $svnpath/trunk &> $TESTING/svn ; then
+ report "failed to update svn sources with"
+ report "svn switch -r $svn_revision $svnpath/trunk"
+ freport $TESTING/svn
+ return 1
+ fi
+ ;;
+
+ ${svnpath}*)
+ if ! svn switch -r $svn_revision $svn_branch &> $TESTING/svn ; then
+ report "failed to update svn sources with"
+ report "svn switch -r $svn_revision $svn_branch"
+ freport $TESTING/svn
+ return 1
+ fi
+ ;;
+
+ *)
+ if ! svn switch -r $svn_revision $svnpath/branches/$svn_branch &> $TESTING/svn ; then
+ report "failed to update svn sources with"
+ report "svn switch -r $svn_revision $svnpath/branches/$svn_branch"
+ freport $TESTING/svn
+ return 1
+ fi
+ ;;
+ esac
+ contrib/gcc_update --touch
+
+ current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
+ if [[ $VERSION < $current_version ]]; then
+ if [ -f $SOURCE/contrib/patch_tester.sh ]; then
+ selfexec
+ fi
+ fi
+
+ return 0
+}
+
+apply_patch () {
+ if [ $nogpg = false ]; then
+ if ! gpg --batch --verify $PATCH &> $TESTING/gpgverify ; then
+ report "your patch failed to verify:"
+ freport $TESTING/gpgverify
+ return 1
+ fi
+ fi
+
+ cd $SOURCE
+ if ! patch -p0 < $PATCH &> $TESTING/patching ; then
+ report "your patch failed to apply:"
+ report "(check that the patch was created at the top level)"
+ freport $TESTING/patching
+ return 1
+ fi
+
+ # Just assume indexes for now -- not really great, but svn always
+ # makes them.
+ grep "^Index: " $PATCH | sed -e 's/Index: //' | while read file; do
+ # If the patch resulted in an empty file, delete it.
+ # This is how svn reports deletions.
+ if [ ! -s $file ]; then
+ rm -f $file
+ report "Deleting empty file $file"
+ fi
+ done
+}
+
+save_compilers () {
+ for COMPILER in $COMPILERS ; do
+ if [ -f $BUILD/$COMPILER ]; then
+ cp $BUILD/$COMPILER $PRISTINE
+ fi
+ done
+}
+
+bootntest () {
+ rm -rf $BUILD
+ mkdir $BUILD
+ cd $BUILD
+
+ CONFIG_OPTIONS=`grep "^configure:" $PATCH | sed -e "s/^configure://g"`
+ CONFIG_OPTIONS="$default_config $CONFIG_OPTIONS"
+ if ! eval $SOURCE/configure $CONFIG_OPTIONS &> $1/configure ; then
+ report "configure with `basename $1` version failed with:"
+ freport $1/configure
+ return 1
+ fi
+
+ MAKE_ARGS=`grep "^make:" $PATCH | sed -e "s/^make://g"`
+ MAKE_ARGS="$default_make $MAKE_ARGS"
+ if ! eval make $dashj $MAKE_ARGS &> $1/bootstrap ; then
+ report "bootstrap with `basename $1` version failed with last lines:"
+ tail -30 $1/bootstrap > $1/last_bootstrap
+ freport $1/last_bootstrap
+ report "grep --context=20 Error bootstrap:"
+ grep --context=20 Error $1/bootstrap > $1/bootstrap_error
+ freport $1/bootstrap_error
+ return 1
+ fi
+
+ CHECK_OPTIONS=`grep "^check:" $PATCH | sed -e "s/^check://g"`
+ CHECK_OPTIONS="$default_check $CHECK_OPTIONS"
+ eval make $dashj $CHECK_OPTIONS -k check &> $1/check
+
+ SUITESRUN="`grep 'Summary ===' $1/check | cut -d' ' -f 2 | sort`"
+ if [ x$SUITESRUN = x ]; then
+ report "check with `basename $1` version failed, no testsuites were run"
+ return 1
+ fi
+
+ for LOG in $TESTLOGS ; do
+ if [ -f $BUILD/$LOG ]; then
+ mv $BUILD/$LOG $1
+ mv `echo "$BUILD/$LOG" | sed -e "s/\.sum/\.log/g"` $1
+ fi
+ done
+
+ return 0
+}
+
+bootntest_patched () {
+ cleanup
+ mkdir -p $PATCHED
+ apply_patch && bootntest $PATCHED
+ return $?
+}
+
+# Build the pristine tree with exactly the same options as the patch under test.
+bootntest_pristine () {
+ cleanup
+ current_branch=`svn info $SOURCE | grep "^URL:" | sed -e "s/URL: //g" -e "s,${svnpath},,g"`
+ current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
+ PRISTINE=$STATE/$current_branch/$current_version
+
+ if [ $nopristinecache = true ]; then
+ rm -rf $PRISTINE
+ fi
+ if [ -d $PRISTINE ]; then
+ ln -s $PRISTINE $TESTING/pristine
+ return 0
+ else
+ mkdir -p $PRISTINE
+ ln -s $PRISTINE $TESTING/pristine
+ bootntest $PRISTINE
+ RETVAL=$?
+ if [ $RETVAL = 0 -a $savecompilers = true ]; then
+ save_compilers
+ fi
+ return $RETVAL
+ fi
+}
+
+regtest () {
+ touch $1/report
+ touch $1/passes
+ touch $1/failed
+ touch $1/regress
+
+ for LOG in $TESTLOGS ; do
+ NLOG=`basename $LOG`
+ if [ -f $1/$NLOG ]; then
+ awk '/^FAIL: / { print "'$NLOG'",$2; }' $1/$NLOG
+ fi
+ done | sort | uniq > $1/failed
+
+ comm -12 $1/failed $1/passes >> $1/regress
+ NUMREGRESS=`wc -l < $1/regress | tr -d ' '`
+
+ if [ $NUMREGRESS -eq 0 ] ; then
+ for LOG in $TESTLOGS ; do
+ NLOG=`basename $LOG`
+ if [ -f $1/$NLOG ] ; then
+ awk '/^PASS: / { print "'$NLOG'",$2; }' $1/$NLOG
+ fi
+ done | sort | uniq | comm -23 - $1/failed > $1/passes
+ echo "there are no regressions with your patch." >> $1/report
+ else
+ echo "with your patch there are $NUMREGRESS regressions." >> $1/report
+ echo "list of regressions with your patch:" >> $1/report
+ cat $1/regress >> $1/report
+ fi
+}
+
+contrib_compare_tests () {
+ report "comparing logs with contrib/compare_tests:"
+ for LOG in $TESTLOGS ; do
+ NLOG=`basename $LOG`
+ if [ -f $PRISTINE/$NLOG -a -f $PATCHED/$NLOG ]; then
+ $SOURCE/contrib/compare_tests $PRISTINE/$NLOG $PATCHED/$NLOG > $TESTING/compare_$NLOG
+ freport $TESTING/compare_$NLOG
+ fi
+ done
+}
+
+compare_passes () {
+ regtest $PRISTINE
+ cp $PRISTINE/passes $PATCHED
+ regtest $PATCHED
+ freport $PATCHED/report
+ report "FAILs with patched version:"
+ freport $PATCHED/failed
+ report "FAILs with pristine version:"
+ freport $PRISTINE/failed
+
+ # contrib_compare_tests
+}
+
+write_report () {
+ backup_patched=$STATE/patched/`now`
+ report "The files used for the validation of your patch are stored in $backup_patched on the tester machine."
+
+ EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
+ if [ x$EMAIL != x ]; then
+ mutt -s "[regtest] Results for `basename $PATCH` on $TARGET" -i $REPORT -a $PATCH $EMAIL
+ fi
+
+ mv $TESTING $backup_patched
+}
+
+announce () {
+ EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
+ if [ x$EMAIL != x ]; then
+
+ START_REPORT=$TESTING/start_report
+ echo "Hi, " >> $START_REPORT
+ echo "I'm the automatic tester running on $TARGET." >> $START_REPORT
+ echo "I just started to look at your patch `basename $PATCH`." >> $START_REPORT
+ echo "Bye, your automatic tester." >> $START_REPORT
+ mutt -s "[regtest] Starting bootstrap for `basename $PATCH` on $TARGET" -i $START_REPORT $EMAIL
+ fi
+}
+
+# After selfexec, $TESTING is already set up.
+if [ -d $TESTING ]; then
+ # The only file in $TESTING is the patch.
+ PATCH=`ls -rt -1 $TESTING | head -1`
+ PATCH=$TESTING/$PATCH
+ if [ -f $PATCH ]; then
+ bootntest_patched && bootntest_pristine && compare_passes
+ write_report
+ fi
+fi
+
+firstpatch=true
+while true; do
+ PATCH=`ls -rt -1 $PATCHES | head -1`
+ if [ x$PATCH = x ]; then
+ if [ $stop = true ]; then
+ if [ $firstpatch = true ]; then
+ echo "No patches ready to test, quitting."
+ exit 1
+ else
+ echo "No more patches to test."
+ exit 0
+ fi
+ fi
+ sleep ${standby}m
+ else
+ firstpatch=false
+ sysload=`uptime | cut -d, -f 5`
+ if [[ $sysload > $watermark ]]; then
+ # Wait a bit when system load is too high.
+ sleep ${standby}m
+ else
+ mkdir -p $TESTING
+ mv $PATCHES/$PATCH $TESTING/
+ PATCH=$TESTING/$PATCH
+
+ announce
+ update && bootntest_patched && bootntest_pristine && compare_passes
+ write_report
+ fi
+ fi
+done