Skip to content
Snippets Groups Projects
check_commit_testprogs.sh 17.6 KiB
Newer Older
RIETTE Sébastien's avatar
RIETTE Sébastien committed
#set -x
set -o pipefail #abort if left command on a pipe fails

#This script:
# - compiles the PHYEX package using a specific commit
# - runs the different test progs and checks if results are identical to a given version

#ice_adjust: the ice adjust test case

#ref is commit 855b8f8 for ice_adjust, rain_ice
#ref is commit 7e44ab1 for shallow
#ref is commit e070d16 for rain_ice_old

#Commit e070d16 can be used for rain_ice_old (ref commit for this testprogs), and for
#turb, shallow, rain_ice and ice_adjust (as it gives the same results for these test cases).

#Some modifications have been introduced and new reference commit is 00148b1

#Data generation:
# - The last commit of the testprogs_data branch (based on 46t1) is able to produce the data
#   for the turb, shallow, rain_ice and ice_adjust testprogs. The code is present but must be
#   activated in the corresponding aro_* routine (as only one set of data can be produced during
#   a single execution).
# - The last commit of the testprogs_data2 branch (based on 48t3) is able to produce the data
#   for the rain_ice_old testprog.
#######################
#### CONFIGURATION ####
#######################

#Special pack names:
# - ref: symbolic name to the commit to use as a reference
#        useless for the commits containing a json file
specialName="ref"

#About the tests:
# - ALLTests is a list of tests to be done when '-t ALL' is used. This list is filled here
#   in case there is no ial_version.json file containig a 'testing' section. If this 'testing'
#   section exists, this list is overridden.
# - allowedTests is the list of allowed tests which can depend on platform, if we ask to perform an action
#   with a test not in the allowedTests list, the action is ignored
# - defaultTest is the list of tests to perform when no '-t' option is provided on the command line.
ALLTests="ice_adjust,rain_ice,rain_ice_old,turb,shallow"
defaultTest=${ALLTests}
allowedTests=${ALLTests}

separator='_' #- seprator must be in sync with prep_code.sh separator

PHYEXTOOLSDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

dirdata=$PHYEXTOOLSDIR/testprogs_data
if [ $(hostname | cut -c 1-7) == 'belenos' -o $(hostname | cut -c 1-7) == 'taranis' ]; then
  defaultarchfile=MIMPIIFC1805.EPONA
elif [ $(hostname) == 'aurora01' ]; then
  defaultarchfile=ECMWF_NEC440MPI225SP.AU.x
  defaultarchfile=gnu
#Options to have longer simulations, tag is used to build the directory name of the result
declare -A conf_extra_tag
declare -A conf_extra_opts
i=-1
i=$((i+1)); conf_extra_tag[$i]=""
            conf_extra_opts[$i]=""
i=$((i+1)); conf_extra_tag[$i]="_Z120_NPRO32_BLK1024"
            conf_extra_opts[$i]="--nflevg 120 --nproma 32 --blocks 1024"
i=$((i+1)); conf_extra_tag[$i]="_Z120_NPRO32_BLK256_TIMES4"
            conf_extra_opts[$i]="--nflevg 120 --nproma 32 --blocks 256 --times 4"
i=$((i+1)); conf_extra_tag[$i]="_Z120_NPRO32_BLK64_TIMES16"
            conf_extra_opts[$i]="--nflevg 120 --nproma 32 --blocks 64 --times 16"
i=$((i+1)); conf_extra_tag[$i]='_Z120_NPRO${NPROMA}_BLK${NBLOCKS}'
            conf_extra_opts[$i]='--nflevg 120 --nproma ${NPROMA} --blocks ${NBLOCKS}'
################################
#### COMMAND LINE ARGUMENTS ####
################################

function usage {
  echo "Usage: $0 [-h] [-p] [-c] [-r] [-C] [-s] [--noexpand] [-t TEST] [--repo-user USER] [--repo-protocol PROTOCOL] [-a ARCH] [-A ARCH] [--remove] [--onlyIfNeeded] [--computeRefIfNeeded] [--no-perf] [--no-check] [-e EXTRAPOLATION] commit [reference]"
  echo "commit          commit hash (or a directory, or among $specialName) to test"
  echo "reference       commit hash (or a directory, or among $specialName) REF to use as a reference"
  echo "-s              suppress compilation directory"
  echo "-c              performs compilation"
  echo "-r              runs the tests"
  echo "-C              checks the result against the reference"
  echo "-t TEST         comma separated list of tests to execute"
  echo "                or ALL to execute all tests"
  echo "--noexpand      do not expand mnh_expand blocks (code will be in array-syntax)"
  echo "--repo-user USER"
  echo "                user hosting the PHYEX repository on github,"
  echo "                defaults to the env variable PHYEXREOuser (=$PHYEXREOuser)"
  echo "--repo-protocol PROTOCOL"
  echo "                protocol (https or ssh) to reach the PHYEX repository on github,"
  echo "                defaults to the env variable PHYEXREOprotocol (=$PHYEXREOprotocol)"
  echo "--remove        removes the pack"
  echo "--onlyIfNeeded  do not rerun already run steps"
  echo "--computeRefIfNeeded"
  echo "                compute the reference if not already present"
  echo "--no-perf       deactivate DR_HOOK"
  echo "--no-check      suppress value printing (comparison will be impossible)"
  echo "                this option can reduce drastically the running time but only allow"
  echo "                to access performance statistics."
  echo "-a arch ARCH    architecture name to use to build and run the commit (=$defaultarchfile)"
  echo "-A arch ARCH    architecture name to use for the reference simulation (=$defaultarchfile)"
  echo "-e EXTRAPOLATION"
  echo "                extrapolate data. EXTRAPOLATION corresponds to a configuration:"
  for i in $(seq 1 $((${#conf_extra_tag[@]}-1))); do
    echo "                  - '$i': ${conf_extra_opts[$i]} (${conf_extra_tag[$i]})"
  done
  echo "If nothing is asked (pack creation compilation, running, check, removing) everything"
  echo "except the removing is done"
  echo
  echo "If no test is aked for, the default one ($defaultTest) is executed"
  echo
  echo "With the special reference REF commit, a suitable reference is guessed"
  echo
  echo "The directory (for commit only, not ref) can take the form server:directory"
  echo
  echo "If using a directory (for commit or reference) it must contain at least one '/'"
  echo "The commit can be a tag, written with syntagx tags/<TAG>"
compilation=0
run=0
check=0
commit=""
reference=""
tests=""
suppress=0
archfile=$defaultarchfile
refarchfile=$defaultarchfile

while [ -n "$1" ]; do
  case "$1" in
    '-s') suppress=1;;
    '-c') compilation=1;;
    '-r') run=$(($run+1));;
    '-C') check=1;;
    '-t') tests="$2"; shift;;
    '--repo-user') export PHYEXREPOuser=$2; shift;;
    '--repo-protocol') export PHYEXREPOprotocol=$2; shift;;
    '-a') archfile="$2"; shift;;
    '-A') refarchfile="$2"; shift;;
    '--onlyIfNeeded') onlyIfNeeded=1;;
    '--computeRefIfNeeded') computeRefIfNeeded=1;;
    #--) shift; break ;;
     *) if [ -z "${commit-}" ]; then
          commit=$1
        else
          if [ -z "${reference-}" ]; then
            reference=$1
          else
            echo "Only two commit hash allowed on command line"
            exit 1
          fi
        fi;;
  esac
  shift
done

     $run -eq 0 -a \
     $check -eq 0 -a \
     $remove -eq 0 ]; then
  compilation=1
  run=1
  check=1
fi

if [ -z "${commit-}" ]; then
  echo "At least one commit hash must be provided on command line"
  exit 2
fi

if [ $check -eq 1 -a -z "${reference-}" ]; then
  echo "To perform a comparison two commit hashes are mandatory on the command line"
  exit 3
fi

if [[ ! -z "${conf_extra_tag[$extrapolation]+unset}" ]]; then
  extrapolation_tag=$(eval echo ${conf_extra_tag[$extrapolation]})
else
  echo "The extrapolation option ($extrapolation) doesn't have associated tag"
fi
if [[ ! -z "${conf_extra_opts[$extrapolation]+unset}" ]]; then
  extrapolation_opts=$(eval echo ${conf_extra_opts[$extrapolation]})
else
  echo "The extrapolation option ($extrapolation) doesn't have associated options"
fi

##############################
#### FUNCTION DEFINITIONS ####
##############################

function json_dictkey2value {
  # $1 must contain the json string
  # $2 must be the key name
  # $3 is the default value
  json_content="$1" python3 -c "import json; import os; result=json.loads(os.environ['json_content']).get('$2', '$3'); print(json.dumps(result) if isinstance(result, dict) else result)"
}

###########################
#### COMMIT ADAPTATION ####
###########################

#Name and directory for compiling and executing user pack
declare -A refByTest
if echo $commit | grep '/' | grep -v '^tags/' > /dev/null; then
  name=$(echo $commit | sed 's/\//'${separator}'/g' | sed 's/:/'${separator}'/g' | sed 's/\./'${separator}'/g')
  content_testprogs_version=$(scp $commit/src/testprogs/testprogs_version.json /dev/stdout 2>/dev/null || echo "")
  [ $suppress -eq 1 -a -d $TESTDIR/$name ] && rm -rf $TESTDIR/$name
elif echo $specialName | grep -w $commit > /dev/null; then
  name="$commit"
else
  #The git repository is on github
  if [[ $commit == testprogs${separator}* ]]; then
    testprogs_version_file="testprogs_version.json"
  else
    testprogs_version_file="src/testprogs/testprogs_version.json"
  fi
  if echo $commit | grep '^tags/' > /dev/null; then
    urlcommit=$(echo $commit | cut -d / -f 2-)
  else
    urlcommit=$commit
  fi
  content_testprogs_version=$(wget --no-check-certificate https://raw.githubusercontent.com/$PHYEXREPOuser/PHYEX/${urlcommit}/$testprogs_version_file -O - 2>/dev/null || echo "")
  name="COMMIT$(echo $commit | sed 's/\//'${separator}'/g' | sed 's/:/'${separator}'/g' | sed 's/\./'${separator}'/g')"
  [ $suppress -eq 1 -a -d $TESTDIR/$name ] && rm -rf $TESTDIR/$name
fi
if [ ! "${content_testprogs_version}" == "" ]; then
  testing=$(json_dictkey2value "$content_testprogs_version" 'testing' '')
  refALL=$(json_dictkey2value "$testing" "ALL" '')
  if [ ! "$testing" == "" ]; then
    ALLTests='' #We reset the list of tests
    for t in $(echo $allowedTests | sed 's/,/ /g'); do
      ref=$(json_dictkey2value "$testing" "$t" "$refALL")
      if [ ! "$ref" == "" ]; then
        ALLTests="${ALLTests},$t"
        refByTest[$t]=$ref
      fi
    done
    ALLTests="${ALLTests:1}" #Remove first character (',')
#Name and directory for the reference version
if [ ! -z "${reference-}" ]; then
  declare -A refnameByTest
  #Reference to use for each test
  for t in $(echo $ALLTests | sed 's/,/ /g'); do
    #Name of the reference
    if [ "$reference" == "REF" ]; then
      if [[ ! -z "${refByTest[$t]+unset}" ]]; then #the -v test is valid only with bash > 4.3
        #The json file contained the references to use on a per test case basis
        caseref=${refByTest[$t]}
      else
        caseref=$defaultRef
      fi
      refByTest[$t]=$caseref
    else
      #The exact reference to use was given on the command line
      caseref=$reference
    fi
    refByTest[$t]=$caseref
  
    #Conversion into directory name
    if echo $caseref | grep '/' > /dev/null; then
      refname=$(echo $reference | sed 's/\//'${separator}'/g' | sed 's/:/'${separator}'/g' | sed 's/\./'${separator}'/g')
    elif echo $specialName | grep -w $caseref > /dev/null; then
      refname="$caseref"
    else
      refname="COMMIT${caseref}"
    fi
    refnameByTest[$t]=$refname
  done
fi
if [ -z "${tests-}" ]; then
  tests=$defaultTest
elif echo "$tests" | grep -w 'ALL' > /dev/null; then
  tests=$(echo "$tests" | sed "s/\bALL\b/$ALLTests/g")
fi

#######################
#### PACK CREATION ####
#######################
  if [ -d $TESTDIR/$name/build/with_fcm/arch_${archfile} ]; then
      echo "Directory already exists ($TESTDIR/$name/build/with_fcm/arch_${archfile}),"
      echo "suppress it to be able to compile it again (or use the -s option to automatically suppress it)"
      exit 5
    fi
  else
    echo "### Pack creation for commit $commit"

    if echo $specialName | grep -w $commit > /dev/null; then
      echo "Special commit '$commit' cannot be compiled with this script"
      exit 4
    fi

    if [ ! -d build ]; then
      cp -r $PHYEXTOOLSDIR/../build . #We use the compilation system from the same commit as the current script
      rm -rf build/with_fcm/arch_*
    else
      echo "WARNING: the compilation system is already there, we use it but it could be outdated"
    fi
    cd $TESTDIR/$name/build/with_fcm/
    ./make_fcm.sh -p $useexpand --commit $commit --arch $archfile 2>&1 | tee Output_compilation_step1
#####################
#### COMPILATION ####
#####################

if [ $compilation -eq 1 ]; then
  if [ $onlyIfNeeded -eq 0 -o ! -f $TESTDIR/$name/build/with_fcm/arch_${archfile}/build/bin/libphyex.so ]; then
    echo "### Compilation of commit $commit"
    cd $TESTDIR/$name/build/with_fcm/
    ./make_fcm.sh -c $useexpand --commit $commit --arch $archfile 2>&1 | tee Output_compilation_step2
  fi
###################
#### EXECUTION ####
###################
if [ $run -ge 1 ]; then
  cd $TESTDIR/$name

  #Cleaning to suppress old results that may be confusing in case of a crash during the run
  if [ $onlyIfNeeded -eq 0 ]; then
    for t in $(echo $tests | sed 's/,/ /g'); do
      if [ -d tests/with_fcm/arch_${archfile}/${t}${extrapolation_tag} ]; then
        rm -rf tests/with_fcm/arch_${archfile}/${t}${extrapolation_tag}

  #Run the tests one after the other
  for t in $(echo $tests | sed 's/,/ /g'); do
    if echo $allowedTests | grep -w $t > /dev/null; then #test is allowed on this plateform
      if  [ ! -d tests/with_fcm/arch_${archfile}/${t}${extrapolation_tag} ]; then #We do not enter systematically this part if onlyIfNeeded=1
        if [ $firstrun -eq 1 ]; then
          echo "### Running of commit $commit"
          firstrun=0
        fi

        if [ ! -f $TESTDIR/$name/build/with_fcm/arch_${archfile}/build/bin/main_${t}.exe ]; then
          echo "Directory does not exist ($TESTDIR/$name) or compilation has failed, please check"
          exit 6
        fi

        #execution
        cd $TESTDIR/$name
        mkdir -p tests/with_fcm/arch_${archfile}/${t}${extrapolation_tag}
        cd tests/with_fcm/arch_${archfile}/${t}${extrapolation_tag}
        if [ $perf -eq 1 ]; then
            export DR_HOOK_OPT=prof
            export DR_HOOK=1
            export DR_HOOK_IGNORE_SIGNALS=-1
        . $TESTDIR/$name/build/with_fcm/arch_${archfile}/arch.env
        $TESTDIR/$name/build/with_fcm/arch_${archfile}/build/bin/main_${t}.exe $checkOpt $extrapolation_opts > Output_run 2> Stderr_run
        stat=$?
        set -e
        if [ $stat -ne 0 ]; then
          cat Stderr_run
          exit $stat
        fi
        if [ $perf -eq 1 ]; then
            firstLine=$(grep -m 1 -n "^ *1" drhook.prof.0 | cut -d: -f1)
            python3 -c "import numpy, pandas
d = {'time': ('<f4', ('mean', )), 'self': ('<f4', ('mean', 'max', 'min', 'std', 'sum')),
     'total': ('<f4', ('mean', 'max', 'min', 'std', 'sum')), 'calls': ('<i4', ('sum', )),
     'self_per_call': ('<f4', ('mean', )), 'total_per_call': ('<f4', ('mean', )), 'routine': ('U256', '')}
arraynp = numpy.loadtxt('drhook.prof.0', dtype=[(k, v[0]) for (k, v) in d.items()],
                        converters={8: lambda s: s.split(b'@')[0].lstrip(b'*')},
                        skiprows=$firstLine - 1, usecols=[1, 3, 4, 5, 6, 7, 8])
df = pandas.DataFrame(arraynp).groupby('routine').agg(
      **{k + '_' + agg:pandas.NamedAgg(column=k, aggfunc=agg)
         for (k, agg) in [(k, agg) for k in d.keys() for agg in d[k][1]]
         if k != 'routine'}).sort_values('self_sum', ascending=False)
df.index.name += ' ordered by self_sum'
with open('drhook.prof.agg', 'w') as f: f.write(df.to_string())
"
        fi
if [ $check -eq 1 ]; then
  echo "### Check commit $commit against commit $reference"

  alltests=0
  message=""
  for t in $(echo $tests | sed 's/,/ /g'); do
    if echo $allowedTests | grep -w $t > /dev/null; then
      #Run the reference if needed
      if [ $computeRefIfNeeded -eq 1 ]; then
        $0 -p -c -r -t $t -a ${refarchfile} --onlyIfNeeded -e $extrapolation ${refByTest[$t]}
      file1=$TESTDIR/$name/tests/with_fcm/arch_${archfile}/${t}${extrapolation_tag}/Output_run
      file2=$TESTDIR/${refnameByTest[$t]}/tests/with_fcm/arch_${refarchfile}/${t}${extrapolation_tag}/Output_run
      mess=""
      te=0
      if [ ! -f "$file1" ]; then
        mess="Result ($file1) for commit $commit does not exist, please run the simulation"
        te=1
      fi
      if [ ! -f "$file2" ]; then
        mess2="Result ($file2) for commit ${refByTest[$t]} does not exist, please run the simulation"
        te=1
        if [ "$mess" = "" ]; then
          mess=$mess2
        else
          mess="$mess and $mess2"
        fi
      fi
      if [ $te -eq 0 ]; then
        set +e
        mess=$($PHYEXTOOLSDIR/compare.py --testprogs $file1 $file2)
        te=$?
        set -e
      fi
      [ $te -ne 0 ] && message="$message $mess \n"
      alltests=$(($alltests+$te))
    fi
  done
  if [ $alltests -eq 0 ]; then
    echo "SUCCESS, files are identical"
  else
    echo "*************** Files are different *******************"
    echo -e "$message"
if [ $remove -eq 1 ]; then
  echo "### Remove model directory for commit $commit"
  [ -d $TESTDIR/$name ] && rm -rf $TESTDIR/$name
fi

exit $cmpstatus