1#!/bin/sh
2
3#----------------------------------------------------------------------------
4# Automated build and test for Valgrind.  Compares Valgrind from 24 hours
5# ago with the current one.  See the README.txt on how to run it.
6#----------------------------------------------------------------------------
7
8#----------------------------------------------------------------------------
9# Helper functions
10#----------------------------------------------------------------------------
11
12# Returns the revision number for the source files at date $1 in Subversion
13# repo $2. Note: the "--depth" command line argument is supported from
14# Subversion version 1.5 on.
15get_svn_revision() {
16  (
17    cd $DIR
18    rm -rf infodir
19    if ! svn co -r "{$1}" --depth empty "$2" infodir > /dev/null 2>&1; then
20      # Subversion 1.4 or before.
21      rm -rf infodir
22      svn co -r "{$1}" --non-recursive "$2" infodir > /dev/null
23    fi
24    svn info infodir | sed -n 's/^Revision: //p'
25    rm -rf infodir
26  )
27}
28
29runcmd () {
30   logfile=$1
31   str=$2
32   shift 2
33
34   # Header in short logfile.
35   # We use "printf" to avoid printing a newline;  "echo -n" isn't POSIX and
36   # so isn't supported on all systems.
37   printf "   $str  ... " >> $logfile.short
38
39   # Header and command in verbose logfile
40   printf "   $str  ... " >> $logfile.verbose
41   echo "$*" >> $logfile.verbose
42
43   # Run the command
44   ("${ABT_EVAL}" "$*") >> $logfile.verbose 2>&1
45   res=$?
46
47   # Write result to the short logfile
48   if [ $res = 0 ]
49   then
50      echo "done"   >> $logfile.short
51   else
52      echo "failed" >> $logfile.short
53   fi
54
55   return $res
56}
57
58#----------------------------------------------------------------------------
59# Startup
60#----------------------------------------------------------------------------
61
62valgrind_svn_repo="svn://svn.valgrind.org/valgrind/trunk"
63vex_svn_repo="svn://svn.valgrind.org/vex/trunk"
64
65# Must have exactly two arguments
66if [ $# -ne 2 ] ; then
67    echo "usage: $0 /path/to/valgrind/nightly <tag>"
68    exit 1
69fi
70
71# Get args from command line
72DIR=$1
73TAG=$2
74
75# Get times and date
76START=`date "+%F %H:%M:%S %Z"`
77
78# This is one of the formats SVN accepts.  Yes, the 'T' appears in the final
79# string, it's supposed to be like that.
80svn_date_format="+%Y-%m-%dT%H:%M:%S"
81
82# The time-and-date from 24 hours ago is tricky;  Linux and Darwin have
83# different ways of getting it, so we try things until something works.
84svn_old_date=
85if [ "z" = "z${svn_old_date}" ] ; then
86    # Linux method.
87    svn_old_date=`date --date=yesterday $svn_date_format 2> /dev/null`
88fi
89if [ "z" = "z${svn_old_date}" ] ; then
90    # Darwin method.
91    svn_old_date=`date -v-24H $svn_date_format 2> /dev/null`
92fi
93if [ "z" = "z${svn_old_date}" ] ; then
94    echo "Sorry, can't work out the time and date for 24 hours ago, aborting"
95    exit 1;
96fi
97
98# The time-and-date for now is easy.
99svn_new_date=`date $svn_date_format`
100
101cd $DIR
102
103# Clean up output files produced by a previous run.
104rm -rf diffs diffs.txt diff.short final new.short new.verbose old.short old.verbose
105rm -rf sendmail.log unchanged.log valgrind-old valgrind-new
106
107# Setup any relevant environment variables from conf/<tag>.conf.
108. conf/$TAG.conf
109if [ "${ABT_JOBS}" = "" ]; then
110  ABT_JOBS=1
111fi
112if [ "${ABT_EVAL}" = "" ]; then
113  ABT_EVAL="eval"
114fi
115if [ "${ABT_RUN_REGTEST}" = "" ]; then
116  ABT_RUN_REGTEST="make regtest"
117fi
118
119if [ "${ABT_PERF_TOOLS}" = "" ]; then
120  ABT_PERF_TOOLS="--tools=none,memcheck,callgrind,helgrind,cachegrind,drd,massif"
121fi
122if [ "${ABT_PERF_REPS}" = "" ]; then
123  ABT_PERF_REPS="--reps=3"
124fi
125
126
127#----------------------------------------------------------------------------
128# Check out, build, test
129#----------------------------------------------------------------------------
130
131vg_old_rev="`get_svn_revision ${svn_old_date} ${valgrind_svn_repo}`"
132vg_new_rev="`get_svn_revision ${svn_new_date} ${valgrind_svn_repo}`"
133vex_old_rev="`get_svn_revision ${svn_old_date} ${vex_svn_repo}`"
134vex_new_rev="`get_svn_revision ${svn_new_date} ${vex_svn_repo}`"
135if [ "${vg_old_rev}" = "${vg_new_rev}" -a "${vex_old_rev}" = "${vex_new_rev}" ]
136then
137  echo "Both {$svn_old_date} and {$svn_new_date} correspond to Valgrind r${vg_new_rev} / VEX r${vex_new_rev}"\
138       "-- skipping nightly build." >unchanged.log
139  exit 0
140fi
141
142# Do everything twice -- once for the 24 hours old Valgrind, and once
143# for the current one.
144for logfile in old new ; do
145
146   # Remove old short and verbose log files, and start the new ones
147   for ext in short verbose ; do
148      echo > $logfile.$ext
149   done
150
151   # Choose the current Valgrind, or one from 24 hours ago
152   if [ $logfile = "old" ] ; then
153      svn_date=$svn_old_date
154   else
155      svn_date=$svn_new_date
156   fi
157
158   # Get dates for the old and new versions
159
160   # Check out, build, run tests
161   runcmd $logfile \
162          "Checking out valgrind source tree" \
163          "svn co ${valgrind_svn_repo} -r {$svn_date} valgrind-$logfile\
164           && svn update -r {$svn_date} valgrind-$logfile/VEX" && \
165   \
166   runcmd $logfile \
167          "Configuring valgrind             " \
168          "cd valgrind-$logfile && ./autogen.sh  && ./configure --prefix=`pwd`/valgrind-$logfile/Inst ${ABT_CONFIGURE_OPTIONS}" && \
169   \
170   runcmd $logfile \
171          "Building valgrind                " \
172          "cd valgrind-$logfile && make -j ${ABT_JOBS} && make -j ${ABT_JOBS} check && make install" && \
173   \
174   runcmd $logfile \
175          "Running regression tests         " \
176          "cd valgrind-$logfile && ${ABT_RUN_REGTEST}"
177
178   # Stash away the return code of the regression run
179   regrun_rc=$?
180
181   # Grab some indicative text for the short log file -- if the regtests
182   # succeeded, show their results.  If we didn't make it that far, show the
183   # last 20 lines.
184   egrep -q '^== [0-9]+ tests' $logfile.verbose && (
185      echo >> $logfile.short
186      echo "Regression test results follow" >> $logfile.short
187      echo >> $logfile.short
188      awk '/^== [0-9]+ tests/, /^$/ { print }' $logfile.verbose >> $logfile.short
189   # Check the return code of the regression run; we might have successfully
190   # run all tests but still failed in the post-regtest checks.
191      if [ $regrun_rc != "0" ]; then
192         echo >> $logfile.short
193         echo "Last 20 lines of verbose log follow" >> $logfile.short \
194         echo >> $logfile.short
195         tail -20 $logfile.verbose >> $logfile.short
196      fi
197   ) || (
198      echo >> $logfile.short
199      echo "Last 20 lines of verbose log follow" >> $logfile.short \
200      echo >> $logfile.short
201      tail -20 $logfile.verbose >> $logfile.short
202   )
203done
204
205# if requested, run regression tests and produce results in perflogfile.out
206if [ "${ABT_PERF}" != "" ]; then
207   cd valgrind-new
208   echo ${ABT_PERF_TOOLS} ${ABT_PERF_REPS} ${ABT_PERF} > ../perflogfile
209   (time perl perf/vg_perf ${ABT_PERF_TOOLS} ${ABT_PERF_REPS} ${ABT_PERF} perf) >> ../perflogfile 2>&1
210   cd ..
211fi
212
213
214#----------------------------------------------------------------------------
215# Prepare results and send
216#----------------------------------------------------------------------------
217
218# Get times and date
219END=`date "+%F %H:%M:%S %Z"`
220
221# Gather some information about this run and its environment
222valgrind_revision="`svn info valgrind-new | grep Revision | sed 's/Revision[ ]*:[ ]*//'`"
223vex_revision="`svn info valgrind-new/VEX | grep Revision | sed 's/Revision[ ]*:[ ]*//'`"
224gcc_version="`gcc --version 2> /dev/null | head -1`"
225gdb_version="`gdb --version 2> /dev/null | head -1`"
226as_version="`as --version 2> /dev/null | head -1`"
227libc_so="`ls -1 /lib/libc.so.* /lib64/libc.so.* /lib32/libc.so.* /lib/*-linux-gnu/libc.so.* 2>/dev/null | tail -1`"
228libc="unknown"
229if [ "x$libc_so" != "x" ]; then
230  if [ -e "$libc_so" -a -r "$libc_so" ]; then
231    libc="`$libc_so | head -1`"
232  fi
233fi
234libc=`echo $libc | sed "s/, by Roland.*//"`
235uname_stuff="`uname -mrs`"
236if [ -r /etc/os-release ]; then
237  vendor_stuff="`. /etc/os-release; echo ${NAME} ${VERSION}`"
238elif which lsb_release 2>&1 > /dev/null; then
239  vendor_stuff="`lsb_release -sicr | xargs echo`"
240elif [ -e "/etc/issue.net" -a -r "/etc/issue.net" ]; then
241  vendor_stuff="`cat /etc/issue.net | head -1`"
242else
243  vendor_stuff="unknown"
244fi
245
246echo "valgrind revision: $valgrind_revision" >  final
247echo "VEX revision:      $vex_revision"      >> final
248echo "C compiler:        $gcc_version"       >> final
249echo "GDB:               $gdb_version"       >> final
250echo "Assembler:         $as_version"        >> final
251echo "C library:         $libc"              >> final
252echo "uname -mrs:        $uname_stuff"       >> final
253echo "Vendor version:    $vendor_stuff"      >> final
254
255# 'final' shows the difference between the old and new results
256echo                                              >> final
257echo "Nightly build on" $TAG "(" $ABT_DETAILS ")" >> final
258echo "Started at" $START                          >> final
259echo "Ended   at" $END                            >> final
260
261# If the results differ from 24 hours ago, print extra stuff.
262diff -C1 old.short new.short > diff.short
263changed=$?
264
265if [ $changed != 0 ] ; then
266   echo "Results differ from 24 hours ago"      >> final
267   changed_str=""
268else
269   echo "Results unchanged from 24 hours ago"   >> final
270   changed_str="(unchanged) "
271fi
272
273# Always show the current results.
274cat new.short >> final
275
276if [ $changed != 0 ] ; then
277   echo "=================================================" >> final
278   echo "== Results from 24 hours ago                   ==" >> final
279   echo "=================================================" >> final
280   cat old.short                                            >> final
281
282   echo                                                     >> final
283   echo "=================================================" >> final
284   echo "== Difference between 24 hours ago and now     ==" >> final
285   echo "=================================================" >> final
286   echo                                                     >> final
287   cat diff.short                                           >> final
288   echo                                                     >> final
289fi
290
291# add perf results if requested
292if [ "${ABT_PERF}" != "" ]; then
293   cat perflogfile                                             >> final
294fi
295
296# Gather up the diffs (at most the first 100 lines for each one) into a
297# single file.
298MAX_LINES=100
299diff_files=`find . -name '*.diff*' | sort`
300if [ z"$diff_files" = z ] ; then
301   echo "Congratulations, all tests passed!" >> diffs
302else
303   for i in $diff_files ; do
304      echo "=================================================" >> diffs
305      echo $i                                                  >> diffs
306      echo "=================================================" >> diffs
307      if [ `wc -l < $i` -le $MAX_LINES ] ; then
308         cat $i                                                >> diffs
309      else
310         head -n $MAX_LINES $i                                 >> diffs
311         echo "<truncated beyond $MAX_LINES lines>"            >> diffs
312      fi
313   done
314fi
315
316# Rename diffs into diffs.txt such that it can be viewed easily with an
317# e-mail client.
318mv diffs diffs.txt
319
320# Use the conf/<tag>.sendmail script to email the results.
321conf/$TAG.sendmail \
322   "$changed_str$START nightly build ($TAG, $ABT_DETAILS)" \
323   final \
324   diffs.txt > sendmail.log 2>&1
325