#!/bin/bash -e
#
# generate list.txt and run the test programs
# 2021-05-12 <udo.krebelder@gmx.at>
#

# List of test programs
proglist=(
    test_foobar_lua.sh:Lua
    test_foobar_lua2.sh:Lua
    #test_mikro77_n2.gawk:Gawk
    test_hans.exe:CPP
    test_mikro77_hash.gawk:Gawk
    #test_mh_python3.sh:Python3
    #test_mikro77_n2.exe:CPP
    #test_heinzel.exe:CPP
    test_mikro77_sort.exe:CPP
    test_foobar3.exe:C
    test_heinzel2.exe:CPP
    test_mikro77_hash.exe:CPP
    #test_roger.exe:CPP
    test_foobar2.exe:C
    test_mh_yalu_python3.sh:Python3
    test_mikro77_hash.pl:Perl
    test_jemand_rust.exe:Rust
    test_native_n2.exe:C
    test_native_hash.exe:C
)

if [[ `uname` == MINGW* ]]
then
    proglist+=(test_roger.exe:CPP)
    proglist+=(test_csharp_roger.exe:C#)
    proglist+=(test_csharp_mt_roger.exe:C#,MT)
fi

# number of test data lines and field length
lines=$((100*1000))
length=100
fields=45
use_rand=1

# number of test progam runs, result is the minimum of the runs
runs=3

verbose=1

leave_files=0

# test program input file
f=list.txt

usage() {
    echo "run.sh [-k] [-q] [-u] [-f|--leave-files>] [-r <runs>] [-c <line-count>] [-l <field-length>]"
    echo "  -k, --quick"
    echo "  -q, --quiet"
    echo "  -f, --leave-files"
    exit 1
}

log() { [[ $verbose -eq 0 ]] || echo "$@" >&2; }

cleanup() {
    if [[ $leave_files -eq 0 ]]
    then
        log "removing list.txt nodup.txt nodup_soll.txt"
        rm -f list.txt nodup.txt nodup_soll.txt
    fi
}

trap cleanup EXIT

while (( $# > 0 ))
do
    case "$1" in
    -q | --quiet )
        verbose=0
        shift
        ;;
    -f | --leave-files )
        leave_files=1
        shift
        ;;
    -u | --no-rand )
        use_rand=0
        length=1
        shift
        ;;
    -k | --quick )
        lines=10000
        runs=1
        shift
        ;;
    -r | --runs )
        runs="$2"
        shift 2
        ;;
    -c | --line-count )
        lines="$2"
        shift 2
        ;;
    -l | --field-length )
        length="$2"
        shift 2
        ;;
    * )
        usage
        ;;
    esac
done

log "lines=$lines field-length=$length fields=$fields use_rand=$use_rand runs=$runs"

# generate list.txt using deterministic data
if ! [[ -r $f && $leave_files -eq 1 ]]
then
    log "generating $f"
    ./gen_csv.exe $lines $length $fields $use_rand
fi

# input file must be readable
true <$f || exit

if ! [[ -r nodup_soll.txt && $leave_files -eq 1 ]]
then
    # generate nodup_soll.txt for comparison
    log "generating nodup_soll.txt"
    ./test_hans.exe
    cp nodup.txt nodup_soll.txt
fi

# lines and bytes in input file
real_lines=`wc -l < $f`
real_bytes=`wc -c < $f`

log "list.txt has $real_lines lines and $real_bytes bytes"

# floating point calculator
xcalc() { gawk "BEGIN { print $1; }"; }

# return minimum of first and second floating point number
xmin() { gawk "BEGIN { if ($1 < $2) print $1; else print $2; }"; }

# run program $runs times and return minimum runtime as floating point number
xtime() {
    test -x "$1" || { log "$1 not executable"; exit 1; }
    tmin=1e99
    (( $runs == 1 || $verbose <= 1 )) || echo -n "=> $1" >&2
    for (( i=0; i < runs; i++ ))
    do
        t=`/usr/bin/time -f%e $1 2>&1`
        tmin=`xmin $tmin $t`
        (( $runs == 1 || $verbose <= 1 )) || echo -n " $tmin" >&2
    done
    (( $runs == 1 || $verbose <= 1 )) || echo "" >&2
    echo $tmin
}

# for each program...
for entry in "${proglist[@]}"
do
    IFS=':' read prog lang comment <<< "$entry";

    sec=`xtime ./$prog`

    # check result
    diff -q nodup.txt nodup_soll.txt

    bps=`xcalc "$real_bytes / $sec * 1e-6"`
    lps=`xcalc "$real_lines / $sec * 1e0"`
    progbytes=`wc -c < $prog`

    #printf '%-24s %-8s Bytes=%-8d Seconds=%-6.1f MB/sec=%-7.1f Lines/sec=%-6.0f\n' \
    # $prog $lang $progbytes $sec $bps $lps
    printf '%-24s %-8s Bytes=%-8d Seconds=%-6.2f MB/sec=%-7.1f\n' \
        $prog $lang $progbytes $sec $bps
done #| sort -k5V
