1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# Used to compare sstate checksums between MACHINES. 6*4882a593Smuzhiyun# Execute script and compare generated list.M files. 7*4882a593Smuzhiyun# Using bash to have PIPESTATUS variable. 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun# It's also usefull to keep older sstate checksums 10*4882a593Smuzhiyun# to be able to find out why something is rebuilding 11*4882a593Smuzhiyun# after updating metadata 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun# $ diff \ 14*4882a593Smuzhiyun# sstate-diff/1349348392/fake-cortexa8/list.M \ 15*4882a593Smuzhiyun# sstate-diff/1349348392/fake-cortexa9/list.M \ 16*4882a593Smuzhiyun# | wc -l 17*4882a593Smuzhiyun# 538 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun# Then to compare sigdata use something like: 20*4882a593Smuzhiyun# $ ls sstate-diff/1349348392/*/armv7a-vfp-neon*/linux-libc-headers/*do_configure*sigdata* 21*4882a593Smuzhiyun# sstate-diff/1349348392/fake-cortexa8/armv7a-vfp-neon-oe-linux-gnueabi/linux-libc-headers/3.4.3-r0.do_configure.sigdata.cb73b3630a7b8191e72fc469c5137025 22*4882a593Smuzhiyun# sstate-diff/1349348392/fake-cortexa9/armv7a-vfp-neon-oe-linux-gnueabi/linux-libc-headers/3.4.3-r0.do_configure.sigdata.f37ada177bf99ce8af85914df22b5a0b 23*4882a593Smuzhiyun# $ bitbake-diffsigs stamps.1349348392/*/armv7a-vfp-neon*/linux-libc-headers/*do_configure*sigdata* 24*4882a593Smuzhiyun# basehash changed from 8d0bd67bb1da6f68717760fc3ef43171 to e869fa61426e88e9c30726ba88a1216a 25*4882a593Smuzhiyun# Variable TUNE_CCARGS value changed from -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon -mtune=cortex-a8 to -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon -mtune=cortex-a9 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun# Global vars 28*4882a593Smuzhiyuntmpdir= 29*4882a593Smuzhiyunmachines= 30*4882a593Smuzhiyuntargets= 31*4882a593Smuzhiyundefault_machines="qemuarm qemux86 qemux86-64" 32*4882a593Smuzhiyundefault_targets="core-image-base" 33*4882a593Smuzhiyunanalyze="N" 34*4882a593Smuzhiyun 35*4882a593Smuzhiyunusage () { 36*4882a593Smuzhiyun cat << EOF 37*4882a593SmuzhiyunWelcome to utility to compare sstate checksums between different MACHINEs. 38*4882a593Smuzhiyun$0 <OPTION> 39*4882a593Smuzhiyun 40*4882a593SmuzhiyunOptions: 41*4882a593Smuzhiyun -h, --help 42*4882a593Smuzhiyun Display this help and exit. 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun --tmpdir=<tmpdir> 45*4882a593Smuzhiyun Specify tmpdir, will use the environment variable TMPDIR if it is not specified. 46*4882a593Smuzhiyun Something like /OE/oe-core/tmp-eglibc (no / at the end). 47*4882a593Smuzhiyun 48*4882a593Smuzhiyun --machines=<machines> 49*4882a593Smuzhiyun List of MACHINEs separated by space, will use the environment variable MACHINES if it is not specified. 50*4882a593Smuzhiyun Default value is "qemuarm qemux86 qemux86-64". 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun --targets=<targets> 53*4882a593Smuzhiyun List of targets separated by space, will use the environment variable TARGETS if it is not specified. 54*4882a593Smuzhiyun Default value is "core-image-base". 55*4882a593Smuzhiyun 56*4882a593Smuzhiyun --analyze 57*4882a593Smuzhiyun Show the differences between MACHINEs. It assumes: 58*4882a593Smuzhiyun * First 2 MACHINEs in --machines parameter have the same TUNE_PKGARCH 59*4882a593Smuzhiyun * Third optional MACHINE has different TUNE_PKGARCH - only native and allarch recipes are compared). 60*4882a593Smuzhiyun * Next MACHINEs are ignored 61*4882a593SmuzhiyunEOF 62*4882a593Smuzhiyun} 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun# Print error information and exit. 65*4882a593Smuzhiyunecho_error () { 66*4882a593Smuzhiyun echo "ERROR: $1" >&2 67*4882a593Smuzhiyun exit 1 68*4882a593Smuzhiyun} 69*4882a593Smuzhiyun 70*4882a593Smuzhiyunwhile [ -n "$1" ]; do 71*4882a593Smuzhiyun case $1 in 72*4882a593Smuzhiyun --tmpdir=*) 73*4882a593Smuzhiyun tmpdir=`echo $1 | sed -e 's#^--tmpdir=##' | xargs readlink -e` 74*4882a593Smuzhiyun [ -d "$tmpdir" ] || echo_error "Invalid argument to --tmpdir" 75*4882a593Smuzhiyun shift 76*4882a593Smuzhiyun ;; 77*4882a593Smuzhiyun --machines=*) 78*4882a593Smuzhiyun machines=`echo $1 | sed -e 's#^--machines="*\([^"]*\)"*#\1#'` 79*4882a593Smuzhiyun shift 80*4882a593Smuzhiyun ;; 81*4882a593Smuzhiyun --targets=*) 82*4882a593Smuzhiyun targets=`echo $1 | sed -e 's#^--targets="*\([^"]*\)"*#\1#'` 83*4882a593Smuzhiyun shift 84*4882a593Smuzhiyun ;; 85*4882a593Smuzhiyun --analyze) 86*4882a593Smuzhiyun analyze="Y" 87*4882a593Smuzhiyun shift 88*4882a593Smuzhiyun ;; 89*4882a593Smuzhiyun --help|-h) 90*4882a593Smuzhiyun usage 91*4882a593Smuzhiyun exit 0 92*4882a593Smuzhiyun ;; 93*4882a593Smuzhiyun *) 94*4882a593Smuzhiyun echo "Invalid arguments $*" 95*4882a593Smuzhiyun echo_error "Try '$0 -h' for more information." 96*4882a593Smuzhiyun ;; 97*4882a593Smuzhiyun esac 98*4882a593Smuzhiyundone 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun# tmpdir directory, use environment variable TMPDIR 101*4882a593Smuzhiyun# if it was not specified, otherwise, error. 102*4882a593Smuzhiyun[ -n "$tmpdir" ] || tmpdir=$TMPDIR 103*4882a593Smuzhiyun[ -n "$tmpdir" ] || echo_error "No tmpdir found!" 104*4882a593Smuzhiyun[ -d "$tmpdir" ] || echo_error "Invalid tmpdir \"$tmpdir\"" 105*4882a593Smuzhiyun[ -n "$machines" ] || machines=$MACHINES 106*4882a593Smuzhiyun[ -n "$machines" ] || machines=$default_machines 107*4882a593Smuzhiyun[ -n "$targets" ] || targets=$TARGETS 108*4882a593Smuzhiyun[ -n "$targets" ] || targets=$default_targets 109*4882a593Smuzhiyun 110*4882a593SmuzhiyunOUTPUT=${tmpdir}/sstate-diff/`date "+%s"` 111*4882a593Smuzhiyundeclare -i RESULT=0 112*4882a593Smuzhiyun 113*4882a593Smuzhiyunfor M in ${machines}; do 114*4882a593Smuzhiyun [ -d ${tmpdir}/stamps/ ] && find ${tmpdir}/stamps/ -name \*sigdata\* | xargs rm -f 115*4882a593Smuzhiyun mkdir -p ${OUTPUT}/${M} 116*4882a593Smuzhiyun export MACHINE=${M} 117*4882a593Smuzhiyun bitbake -S none ${targets} 2>&1 | tee -a ${OUTPUT}/${M}/log; 118*4882a593Smuzhiyun RESULT+=${PIPESTATUS[0]} 119*4882a593Smuzhiyun if ls ${tmpdir}/stamps/* >/dev/null 2>/dev/null ; then 120*4882a593Smuzhiyun cp -ra ${tmpdir}/stamps/* ${OUTPUT}/${M} 121*4882a593Smuzhiyun find ${OUTPUT}/${M} -name \*sigdata\* | sed "s#${OUTPUT}/${M}/##g" | sort > ${OUTPUT}/${M}/list 122*4882a593Smuzhiyun M_UNDERSCORE=`echo ${M} | sed 's/-/_/g'` 123*4882a593Smuzhiyun sed "s/^${M_UNDERSCORE}-/MACHINE/g" ${OUTPUT}/${M}/list | sort > ${OUTPUT}/${M}/list.M 124*4882a593Smuzhiyun find ${tmpdir}/stamps/ -name \*sigdata\* | xargs rm -f 125*4882a593Smuzhiyun else 126*4882a593Smuzhiyun printf "ERROR: no sigdata files were generated for MACHINE $M in ${tmpdir}/stamps\n"; 127*4882a593Smuzhiyun fi 128*4882a593Smuzhiyundone 129*4882a593Smuzhiyun 130*4882a593SmuzhiyunCOMPARE_TASKS="do_configure.sigdata do_populate_sysroot.sigdata do_package_write_ipk.sigdata do_package_write_rpm.sigdata do_package_write_deb.sigdata do_package_write_tar.sigdata" 131*4882a593Smuzhiyun 132*4882a593Smuzhiyunfunction compareSignatures() { 133*4882a593Smuzhiyun MACHINE1=$1 134*4882a593Smuzhiyun MACHINE2=$2 135*4882a593Smuzhiyun PATTERN="$3" 136*4882a593Smuzhiyun PRE_PATTERN="" 137*4882a593Smuzhiyun [ -n "${PATTERN}" ] || PRE_PATTERN="-v" 138*4882a593Smuzhiyun [ -n "${PATTERN}" ] || PATTERN="MACHINE" 139*4882a593Smuzhiyun for TASK in $COMPARE_TASKS; do 140*4882a593Smuzhiyun printf "\n\n === Comparing signatures for task ${TASK} between ${MACHINE1} and ${MACHINE2} ===\n" | tee -a ${OUTPUT}/signatures.${MACHINE2}.${TASK}.log 141*4882a593Smuzhiyun diff ${OUTPUT}/${MACHINE1}/list.M ${OUTPUT}/${MACHINE2}/list.M | grep ${PRE_PATTERN} "${PATTERN}" | grep ${TASK} > ${OUTPUT}/signatures.${MACHINE2}.${TASK} 142*4882a593Smuzhiyun for i in `cat ${OUTPUT}/signatures.${MACHINE2}.${TASK} | sed 's#[^/]*/\([^/]*\)/.*#\1#g' | sort -u | xargs`; do 143*4882a593Smuzhiyun [ -e ${OUTPUT}/${MACHINE1}/*/$i/*${TASK}* ] || echo "INFO: ${i} task ${TASK} doesn't exist in ${MACHINE1}" >&2 144*4882a593Smuzhiyun [ -e ${OUTPUT}/${MACHINE1}/*/$i/*${TASK}* ] || continue 145*4882a593Smuzhiyun [ -e ${OUTPUT}/${MACHINE2}/*/$i/*${TASK}* ] || echo "INFO: ${i} task ${TASK} doesn't exist in ${MACHINE2}" >&2 146*4882a593Smuzhiyun [ -e ${OUTPUT}/${MACHINE2}/*/$i/*${TASK}* ] || continue 147*4882a593Smuzhiyun printf "ERROR: $i different signature for task ${TASK} between ${MACHINE1} and ${MACHINE2}\n"; 148*4882a593Smuzhiyun bitbake-diffsigs ${OUTPUT}/${MACHINE1}/*/$i/*${TASK}* ${OUTPUT}/${MACHINE2}/*/$i/*${TASK}*; 149*4882a593Smuzhiyun echo "$i" >> ${OUTPUT}/failed-recipes.log 150*4882a593Smuzhiyun echo 151*4882a593Smuzhiyun done | tee -a ${OUTPUT}/signatures.${MACHINE2}.${TASK}.log 152*4882a593Smuzhiyun # don't create empty files 153*4882a593Smuzhiyun ERRORS=`grep "^ERROR.*" ${OUTPUT}/signatures.${MACHINE2}.${TASK}.log | wc -l` 154*4882a593Smuzhiyun if [ "${ERRORS}" != "0" ] ; then 155*4882a593Smuzhiyun echo "ERROR: ${ERRORS} errors found in ${OUTPUT}/signatures.${MACHINE2}.${TASK}.log" 156*4882a593Smuzhiyun RESULT+=${ERRORS} 157*4882a593Smuzhiyun fi 158*4882a593Smuzhiyun done 159*4882a593Smuzhiyun} 160*4882a593Smuzhiyun 161*4882a593Smuzhiyunfunction compareMachines() { 162*4882a593Smuzhiyun [ "$#" -ge 2 ] && compareSignatures $1 $2 163*4882a593Smuzhiyun [ "$#" -ge 3 ] && compareSignatures $1 $3 "\(^< all\)\|\(^< x86_64-linux\)\|\(^< i586-linux\)" 164*4882a593Smuzhiyun} 165*4882a593Smuzhiyun 166*4882a593Smuzhiyunif [ "${analyze}" = "Y" ] ; then 167*4882a593Smuzhiyun compareMachines ${machines} 168*4882a593Smuzhiyunfi 169*4882a593Smuzhiyun 170*4882a593Smuzhiyunif [ "${RESULT}" != "0" -a -f ${OUTPUT}/failed-recipes.log ] ; then 171*4882a593Smuzhiyun cat ${OUTPUT}/failed-recipes.log | sort -u >${OUTPUT}/failed-recipes.log.u && mv ${OUTPUT}/failed-recipes.log.u ${OUTPUT}/failed-recipes.log 172*4882a593Smuzhiyun echo "ERROR: ${RESULT} issues were found in these recipes: `cat ${OUTPUT}/failed-recipes.log | xargs`" 173*4882a593Smuzhiyunfi 174*4882a593Smuzhiyun 175*4882a593Smuzhiyunecho "INFO: Output written in: ${OUTPUT}" 176*4882a593Smuzhiyunexit ${RESULT} 177