Home | History | Annotate | Download | only in valgrind
      1 #!/bin/bash
      2 
      3 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 # This script can be used by waterfall sheriffs to fetch the status
      8 # of Valgrind bots on the memory waterfall and test if their local
      9 # suppressions match the reports on the waterfall.
     10 
     11 set -e
     12 
     13 THISDIR=$(dirname "${0}")
     14 LOGS_DIR=$THISDIR/waterfall.tmp
     15 WATERFALL_PAGE="http://build.chromium.org/p/chromium.memory/builders"
     16 WATERFALL_FYI_PAGE="http://build.chromium.org/p/chromium.memory.fyi/builders"
     17 
     18 download() {
     19   # Download a file.
     20   # $1 = URL to download
     21   # $2 = Path to the output file
     22   # {{{1
     23   if [ "$(which curl)" != "" ]
     24   then
     25     if ! curl -s -o "$2" "$1"
     26     then
     27       echo
     28       echo "Failed to download '$1'... aborting"
     29       exit 1
     30     fi
     31   elif [ "$(which wget)" != "" ]
     32   then
     33     if ! wget "$1" -O "$2" -q
     34     then
     35       echo
     36       echo "Failed to download '$1'... aborting"
     37       exit 1
     38     fi
     39   else
     40     echo "Need either curl or wget to download stuff... aborting"
     41     exit 1
     42   fi
     43   # }}}
     44 }
     45 
     46 fetch_logs() {
     47   # Fetch Valgrind logs from the waterfall {{{1
     48 
     49   # TODO(timurrrr,maruel): use JSON, see
     50   # http://build.chromium.org/p/chromium.memory/json/help
     51 
     52   rm -rf "$LOGS_DIR" # Delete old logs
     53   mkdir "$LOGS_DIR"
     54 
     55   echo "Fetching the list of builders..."
     56   download $1 "$LOGS_DIR/builders"
     57   SLAVES=$(grep "<a href=\"builders\/" "$LOGS_DIR/builders" | \
     58            grep 'td class="box"' | \
     59            sed "s/.*<a href=\"builders\///" | sed "s/\".*//" | \
     60            sort | uniq)
     61 
     62   for S in $SLAVES
     63   do
     64     SLAVE_URL=$1/$S
     65     SLAVE_NAME=$(echo $S | sed -e "s/%20/ /g" -e "s/%28/(/g" -e "s/%29/)/g")
     66     echo -n "Fetching builds by slave '${SLAVE_NAME}'"
     67     download $SLAVE_URL?numbuilds=${NUMBUILDS} "$LOGS_DIR/slave_${S}"
     68 
     69     # We speed up the 'fetch' step by skipping the builds/tests which succeeded.
     70     # TODO(timurrrr): OTOH, we won't be able to check
     71     # if some suppression is not used anymore.
     72     #
     73     # The awk script here joins the lines ending with </td> to make it possible
     74     # to find the failed builds.
     75     LIST_OF_BUILDS=$(cat "$LOGS_DIR/slave_$S" | \
     76                      awk 'BEGIN { buf = "" }
     77                           {
     78                             if ($0 ~ /<\/td>/) { buf = (buf $0); }
     79                             else {
     80                               if (buf) { print buf; buf="" }
     81                               print $0
     82                             }
     83                           }
     84                           END {if (buf) print buf}' | \
     85                      grep "success\|failure" | \
     86                      head -n $NUMBUILDS | \
     87                      grep "failure" | \
     88                      grep -v "failed compile" | \
     89                      sed "s/.*\/builds\///" | sed "s/\".*//")
     90 
     91     for BUILD in $LIST_OF_BUILDS
     92     do
     93       # We'll fetch a few tiny URLs now, let's use a temp file.
     94       TMPFILE=$(mktemp -t memory_waterfall.XXXXXX)
     95       download $SLAVE_URL/builds/$BUILD "$TMPFILE"
     96 
     97       REPORT_FILE="$LOGS_DIR/report_${S}_${BUILD}"
     98       rm -f $REPORT_FILE 2>/dev/null || true  # make sure it doesn't exist
     99 
    100       REPORT_URLS=$(grep -o "[0-9]\+/steps/\(memory\|heapcheck\).*/logs/[0-9A-F]\{16\}" \
    101                     "$TMPFILE" \
    102                     || true)  # `true` is to succeed on empty output
    103       FAILED_TESTS=$(grep -o "[0-9]\+/steps/\(memory\|heapcheck\).*/logs/[A-Za-z0-9_.]\+" \
    104                      "$TMPFILE" | grep -v "[0-9A-F]\{16\}" \
    105                      | grep -v "stdio" || true)
    106 
    107       for REPORT in $REPORT_URLS
    108       do
    109         download "$SLAVE_URL/builds/$REPORT/text" "$TMPFILE"
    110         echo "" >> "$TMPFILE"  # Add a newline at the end
    111         cat "$TMPFILE" | tr -d '\r' >> "$REPORT_FILE"
    112       done
    113 
    114       for FAILURE in $FAILED_TESTS
    115       do
    116         echo -n "FAILED:" >> "$REPORT_FILE"
    117         echo "$FAILURE" | sed -e "s/.*\/logs\///" -e "s/\/.*//" \
    118           >> "$REPORT_FILE"
    119       done
    120 
    121       rm "$TMPFILE"
    122       echo $SLAVE_URL/builds/$BUILD >> "$REPORT_FILE"
    123     done
    124     echo " DONE"
    125   done
    126   # }}}
    127 }
    128 
    129 match_suppressions() {
    130   PYTHONPATH=$THISDIR/../python/google \
    131              python "$THISDIR/test_suppressions.py" $@ "$LOGS_DIR/report_"*
    132 }
    133 
    134 match_gtest_excludes() {
    135   for PLATFORM in "Linux" "Chromium%20Mac" "Chromium%20OS"
    136   do
    137     echo
    138     echo "Test failures on ${PLATFORM}:" | sed "s/%20/ /"
    139     grep -h -o "^FAILED:.*" -R "$LOGS_DIR"/*${PLATFORM}* | \
    140          grep -v "FAILS\|FLAKY" | sort | uniq | \
    141          sed -e "s/^FAILED://" -e "s/^/  /"
    142     # Don't put any operators between "grep | sed" and "RESULT=$PIPESTATUS"
    143     RESULT=$PIPESTATUS
    144 
    145     if [ "$RESULT" == 1 ]
    146     then
    147       echo "  None!"
    148     else
    149       echo
    150       echo "  Note: we don't check for failures already excluded locally yet"
    151       echo "  TODO(timurrrr): don't list tests we've already excluded locally"
    152     fi
    153   done
    154   echo
    155   echo "Note: we don't print FAILS/FLAKY tests and 1200s-timeout failures"
    156 }
    157 
    158 usage() {
    159   cat <<EOF
    160 usage: $0 fetch|match options
    161 
    162 This script can be used by waterfall sheriffs to fetch the status
    163 of Valgrind bots on the memory waterfall and test if their local
    164 suppressions match the reports on the waterfall.
    165 
    166 OPTIONS:
    167    -h      Show this message
    168    -n N    Fetch N builds from each slave.
    169 
    170 COMMANDS:
    171   fetch    Fetch Valgrind logs from the memory waterfall
    172   match    Test the local suppression files against the downloaded logs
    173 
    174 EOF
    175 }
    176 
    177 NUMBUILDS=3
    178 
    179 CMD=$1
    180 if [ $# != 0 ]; then
    181   shift
    182 fi
    183 
    184 # Arguments for "match" are handled in match_suppressions
    185 if [ "$CMD" != "match" ]; then
    186   while getopts hn: OPTION
    187   do
    188     case $OPTION in
    189       h)
    190         usage
    191         exit
    192         ;;
    193       n)
    194         NUMBUILDS=$OPTARG
    195         ;;
    196       ?)
    197         usage
    198         exit
    199         ;;
    200     esac
    201   done
    202   shift $((OPTIND-1))
    203   if [ $# != 0 ]; then
    204     usage
    205     exit 1
    206   fi
    207 fi
    208 
    209 if [ "$CMD" = "fetch" ]; then
    210   echo "Fetching $NUMBUILDS builds"
    211   fetch_logs $WATERFALL_PAGE
    212   fetch_logs $WATERFALL_FYI_PAGE
    213 elif [ "$CMD" = "match" ]; then
    214   match_suppressions $@
    215   match_gtest_excludes
    216 elif [ "$CMD" = "blame" ]; then
    217   echo The blame command died of bitrot. If you need it, please reimplement it.
    218   echo Reimplementation is blocked on http://crbug.com/82688
    219 else
    220   usage
    221   exit 1
    222 fi
    223