Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/bin/bash | 1 #!/bin/bash |
| 2 | 2 |
| 3 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 # This script can be used by waterfall sheriffs to fetch the status | 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 | 8 # of Valgrind bots on the memory waterfall and test if their local |
| 9 # suppressions match the reports on the waterfall. | 9 # suppressions match the reports on the waterfall. |
| 10 | 10 |
| 11 set -e | 11 set -e |
| 12 | 12 |
| 13 THISDIR=$(dirname "${0}") | 13 THISDIR=$(dirname "${0}") |
| 14 LOGS_DIR=$THISDIR/waterfall.tmp | 14 LOGS_DIR=$THISDIR/waterfall.tmp |
| 15 WATERFALL_PAGE="http://build.chromium.org/buildbot/memory/builders" | |
|
M-A Ruel
2010/08/11 13:14:40
Why is this script bash? I think it's starting to
| |
| 15 | 16 |
| 16 download() { | 17 download() { |
| 17 # Download a file. | 18 # Download a file. |
| 18 # $1 = URL to download | 19 # $1 = URL to download |
| 19 # $2 = Path to the output file | 20 # $2 = Path to the output file |
| 20 # {{{1 | 21 # {{{1 |
| 21 if [ x$(which curl) != x ]; then | 22 if [ "$(which curl)" != "" ] |
| 22 if ! curl -s -o "$2" "$1" ; then | 23 then |
| 24 if ! curl -s -o "$2" "$1" | |
| 25 then | |
| 23 echo | 26 echo |
| 24 echo "Failed to download '$1'... aborting" | 27 echo "Failed to download '$1'... aborting" |
| 25 exit 1 | 28 exit 1 |
| 26 fi | 29 fi |
| 27 elif [ x$(which wget) != x ]; then | 30 elif [ "$(which wget)" != "" ] |
| 28 if ! wget "$1" -O "$2" -q ; then | 31 then |
| 32 if ! wget "$1" -O "$2" -q | |
| 33 then | |
| 29 echo | 34 echo |
| 30 echo "Failed to download '$1'... aborting" | 35 echo "Failed to download '$1'... aborting" |
| 31 exit 1 | 36 exit 1 |
| 32 fi | 37 fi |
| 33 else | 38 else |
| 34 echo "Need either curl or wget to download stuff... aborting" | 39 echo "Need either curl or wget to download stuff... aborting" |
| 35 exit 1 | 40 exit 1 |
| 36 fi | 41 fi |
| 37 # }}} | 42 # }}} |
| 38 } | 43 } |
| 39 | 44 |
| 40 fetch_logs() { | 45 fetch_logs() { |
| 41 # Fetch Valgrind logs from the waterfall {{{1 | 46 # Fetch Valgrind logs from the waterfall {{{1 |
| 42 | 47 |
| 43 WATERFALL_PAGE="http://build.chromium.org/buildbot/memory/builders" | |
| 44 | |
| 45 rm -rf "$LOGS_DIR" # Delete old logs | 48 rm -rf "$LOGS_DIR" # Delete old logs |
| 46 mkdir "$LOGS_DIR" | 49 mkdir "$LOGS_DIR" |
| 47 | 50 |
| 48 echo "Fetching the list of builders..." | 51 echo "Fetching the list of builders..." |
| 49 download $WATERFALL_PAGE "$LOGS_DIR/builders" | 52 download $WATERFALL_PAGE "$LOGS_DIR/builders" |
| 50 SLAVES=$(grep "<a href=\"builders\/" "$LOGS_DIR/builders" | \ | 53 SLAVES=$(grep "<a href=\"builders\/" "$LOGS_DIR/builders" | \ |
| 51 sed "s/.*<a href=\"builders\///" | sed "s/\".*//" | \ | 54 sed "s/.*<a href=\"builders\///" | sed "s/\".*//" | \ |
| 52 sort | uniq) | 55 sort | uniq) |
| 53 | 56 |
| 54 for S in $SLAVES | 57 for S in $SLAVES |
| 55 do | 58 do |
| 56 SLAVE_URL=$WATERFALL_PAGE/$S | 59 SLAVE_URL=$WATERFALL_PAGE/$S |
| 57 SLAVE_NAME=$(echo $S | sed "s/%20/ /g" | sed "s/%28/(/g" | sed "s/%29/)/g") | 60 SLAVE_NAME=$(echo $S | sed -e "s/%20/ /g" -e "s/%28/(/g" -e "s/%29/)/g") |
| 58 echo -n "Fetching builds by slave '${SLAVE_NAME}'" | 61 echo -n "Fetching builds by slave '${SLAVE_NAME}'" |
| 59 download $SLAVE_URL "$LOGS_DIR/slave_${S}" | 62 download $SLAVE_URL "$LOGS_DIR/slave_${S}" |
| 60 | 63 |
| 61 # We speed up the 'fetch' step by skipping the builds/tests which succeeded. | 64 # We speed up the 'fetch' step by skipping the builds/tests which succeeded. |
| 62 # TODO(timurrrr): OTOH, we won't be able to check | 65 # TODO(timurrrr): OTOH, we won't be able to check |
| 63 # if some suppression is not used anymore. | 66 # if some suppression is not used anymore. |
| 64 LIST_OF_BUILDS=$(grep "<a href=\"\.\./builders/.*/builds/[0-9]\+.*failed" \ | 67 LIST_OF_BUILDS=$(grep "<a href=\"\.\./builders/.*/builds/[0-9]\+.*failed" \ |
| 65 "$LOGS_DIR/slave_$S" | grep -v "failed compile" | \ | 68 "$LOGS_DIR/slave_$S" | grep -v "failed compile" | \ |
| 66 sed "s/.*\/builds\///" | sed "s/\".*//" | head -n 2) | 69 sed "s/.*\/builds\///" | sed "s/\".*//" | head -n 2) |
| 67 | 70 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 84 echo " DONE" | 87 echo " DONE" |
| 85 done | 88 done |
| 86 # }}} | 89 # }}} |
| 87 } | 90 } |
| 88 | 91 |
| 89 match_suppressions() { | 92 match_suppressions() { |
| 90 PYTHONPATH=$THISDIR/../python/google \ | 93 PYTHONPATH=$THISDIR/../python/google \ |
| 91 python "$THISDIR/test_suppressions.py" "$LOGS_DIR/report_"* | 94 python "$THISDIR/test_suppressions.py" "$LOGS_DIR/report_"* |
| 92 } | 95 } |
| 93 | 96 |
| 97 find_blame() { | |
| 98 # Return the blame list for the first revision for a suppression occured in | |
| 99 # the logs of a given test on a given builder. | |
| 100 # $1 - Name of the builder. | |
| 101 # $2 - Name of the test. | |
| 102 # $3 - Hash of the suppression. | |
| 103 # {{{1 | |
| 104 | |
| 105 # Validate arguments. | |
| 106 if [ "$1" = "" -o "$2" = "" -o "$3" = "" ] | |
| 107 then | |
| 108 echo "Missing arguments, use waterfall.sh blame <builder> <test> <hash>" | |
| 109 exit 1 | |
| 110 fi | |
| 111 | |
| 112 SLAVE_NAME="$(echo "$1" | sed -e "s/ /%20/g" -e "s/(/%28/g" -e "s/)/%29/g")" | |
| 113 if [ ! -f "$LOGS_DIR/slave_$SLAVE_NAME" ] | |
| 114 then | |
| 115 echo "I don't know about builder '$1'. Did you run waterfall.sh fetch?" | |
| 116 exit 1 | |
| 117 fi | |
| 118 | |
| 119 TEST_NAME="memory%20test%3A%20$(echo "$2" | sed -e "s/ /%20/g")" | |
| 120 if ! ls -1 "$LOGS_DIR"/report_${SLAVE_NAME}_*_${TEST_NAME} >/dev/null 2>&1 | |
| 121 then | |
| 122 echo "I don't know about the test '$2'. Did you run waterfall.sh fetch?" | |
| 123 exit 1 | |
| 124 fi | |
| 125 | |
| 126 HASH="#$3#" | |
| 127 if ! echo "$3" | grep -q -e '^[0-9A-F]\{8\}$' | |
| 128 then | |
| 129 echo "The hash '$3' looks strange, it should match ^[0-9A-F]{8}$" | |
| 130 exit 1 | |
| 131 fi | |
| 132 | |
| 133 # Determine the number of the latest build from our cache. | |
| 134 LATEST_BUILD=$(grep -l $HASH "$LOGS_DIR"/report_${SLAVE_NAME}_*_${TEST_NAME} | | |
| 135 sed "s/.*_\\([0-9]*\\)_${TEST_NAME}/\\1/" | sort -rn | head -n 1) | |
| 136 | |
| 137 # Find a version where this hash does not occur. | |
| 138 STEP_SIZE=1 | |
| 139 FIRST_BUILD=$LATEST_BUILD | |
| 140 DOWNLOAD_BASE="$WATERFALL_PAGE/$SLAVE_NAME/builds/" | |
| 141 LOG_FILE="/steps/$TEST_NAME/logs/stdio" | |
| 142 echo -n "Searching for latest revision without this hash" | |
| 143 while true | |
| 144 do | |
| 145 FIRST_BUILD=$(($FIRST_BUILD - $STEP_SIZE)) | |
| 146 if [ $STEP_SIZE -lt 128 ] | |
| 147 then | |
| 148 STEP_SIZE=$(($STEP_SIZE * 2)) | |
| 149 fi | |
| 150 echo -n "." | |
| 151 download \ | |
| 152 "$DOWNLOAD_BASE$FIRST_BUILD$LOG_FILE" \ | |
| 153 /tmp/waterfall.$$.report | |
| 154 if ! grep -ql $HASH /tmp/waterfall.$$.report | |
| 155 then | |
| 156 break | |
| 157 fi | |
| 158 LATEST_BUILD=$FIRST_BUILD | |
| 159 rm -f /tmp/waterfall.$$.report | |
| 160 done | |
| 161 rm -f /tmp/waterfall.$$.report | |
| 162 | |
| 163 # Now search backwards for the first version where this hash occurs. | |
| 164 while [ $(($FIRST_BUILD + 1)) -ne $LATEST_BUILD ] | |
| 165 do | |
| 166 if [ $STEP_SIZE -gt 1 ] | |
| 167 then | |
| 168 STEP_SIZE=$(($STEP_SIZE / 2)) | |
| 169 fi | |
| 170 TEST_BUILD=$(($FIRST_BUILD + $STEP_SIZE)) | |
| 171 echo -n "." | |
| 172 download \ | |
| 173 "$DOWNLOAD_BASE$TEST_BUILD$LOG_FILE" \ | |
| 174 /tmp/waterfall.$$.report | |
| 175 if ! grep -ql $HASH /tmp/waterfall.$$.report | |
| 176 then | |
| 177 FIRST_BUILD=$TEST_BUILD | |
| 178 else | |
| 179 LATEST_BUILD=$TEST_BUILD | |
| 180 fi | |
| 181 rm -f /tmp/waterfall.$$.report | |
| 182 done | |
| 183 echo "" | |
| 184 echo "Hash $HASH occurs in build #$LATEST_BUILD for the first time." | |
| 185 echo -n "Receiving blame list" | |
| 186 download "$DOWNLOAD_BASE$LATEST_BUILD" /tmp/waterfall.$$.report | |
| 187 echo "." | |
| 188 echo -n "Revision: " | |
| 189 awk 'BEGIN{FS="[<> ]"} | |
| 190 /Got Revision:/{print $7}' /tmp/waterfall.$$.report | |
| 191 echo "Blamelist:" | |
| 192 awk 'BEGIN{ STATE=0; FS="[<>]" } | |
| 193 /Blamelist:/{STATE=1} | |
| 194 /<ol>/{if (STATE == 1) STATE=2} | |
| 195 /<li>/{if (STATE == 2) print $3} | |
| 196 /<\/ol>/{STATE=3}' /tmp/waterfall.$$.report | |
| 197 rm -f /tmp/waterfall.$$.report | |
| 198 # }}} | |
| 199 } | |
| 200 | |
| 94 if [ "$1" = "fetch" ] | 201 if [ "$1" = "fetch" ] |
| 95 then | 202 then |
| 96 fetch_logs | 203 fetch_logs |
| 97 elif [ "$1" = "match" ] | 204 elif [ "$1" = "match" ] |
| 98 then | 205 then |
| 99 match_suppressions | 206 match_suppressions |
| 207 elif [ "$1" = "blame" ] | |
| 208 then | |
| 209 find_blame "$2" "$3" "$4" | |
| 100 else | 210 else |
| 101 THISNAME=$(basename "${0}") | 211 THISNAME=$(basename "${0}") |
| 102 echo "Usage: $THISNAME fetch|match" | 212 echo "Usage: $THISNAME fetch|match|blame <builder> <test> <hash>" |
| 103 echo " fetch - Fetch Valgrind logs from the memory waterfall" | 213 echo " fetch - Fetch Valgrind logs from the memory waterfall" |
| 104 echo " match - Test the local suppression files against the downloaded logs" | 214 echo " match - Test the local suppression files against the downloaded logs" |
| 215 echo " blame - Return the blame list for the revision where the suppression" | |
| 216 echo " <hash> occured for the first time in the log for <test> on" | |
| 217 echo " <builder>" | |
| 105 fi | 218 fi |
| OLD | NEW |