#!/usr/bin/env bash

set -e

wai=$(dirname $(readlink -f "$0")) # Current script directory
source ${wai}/config

info () {
    echo -e "\033[0;32m$@\033[0m"
}

abort () {
    echo -e "\033[0;31m$@\033[0m"
    exit 1
}

iperf-run () {
    info "---------- Running iperf test ----------"
    iperf -c ${hostip}
}

pure-read () {
    local clean="${1:-1}"
    local inmem="${2:-0}"
    info "---------- Running pure read experiments (inmem=${inmem},clean=${clean}) ----------"
    info "Ensuring that ina260 devices are connected..."
    for dev in $inadev
    do
        bus=$(echo $dev|cut -d: -f1)
        addr=$(echo $dev|cut -d: -f2)
        [ -z $(ls /sys/kernel/ina260/ |grep "${bus}-.*${addr#0x}") ] && echo ina260 $addr | sudo tee "/sys/bus/i2c/devices/i2c-${bus}/new_device"
        [ -z $(ls /sys/kernel/ina260/ |grep "${bus}-.*${addr#0x}") ] && abort "Cannot connect $dev"
    done
    info "Compiling..."
    make -C ${wai}/pure-read -B
    [ $clean -eq 1 ] && rm -f ${wai}/pure_read_bus*.out
    local ndev=$(echo $inadev|wc -w)
    for usen in $(seq 1 $ndev)
    do
        info "Run $nread read over $usen devices"
        local n=0
        unset pids # Erase previous pids
        for dev in $inadev
        do
            local bus=$(echo $dev|cut -d: -f1)
            local addr=$(echo $dev|cut -d: -f2)
            local devicepath=$(realpath /sys/kernel/ina260/${bus}-*${addr#0x})
            local deviceid=$(basename ${devicepath})
            local logfile=${wai}/pure_read_bus${bus}_addr${addr}_usen${usen}_nread${nread}_inmem${inmem}.out
            echo "${bus}:${addr}:${usen}:${nread}:${deviceid}" > ${logfile}
            /usr/bin/time -f "statsline:%P:%M" ${wai}/pure-read/read $deviceid $nread $inmem &>> ${logfile} &
            pids[${i}]=$!
            n=$(( n + 1 ))
            [ $n -eq $usen ] && break
        done
        # Wait for all pids
        for pid in ${pids[*]}; do
            wait $pid
        done
        sync # Ensure that I/O are applied on sdcard
        info "Beaglebone is resting for ${readrest}s"
        sleep ${readrest}
    done
    # Generate the results
    info "Collecting logs..."
    local csv="${wai}/pure_read.csv"
    [ $clean -eq 1 ] && echo "bus,addr,usen,nread,deviceid,startat,endat,inmem,cpu_usage,resident,timestamp,nsecs,power" > "$csv"
    for logfile in ${wai}/pure_read_bus*inmem${inmem}.out
    do
        local bus=$(head -n1 "$logfile"|cut -d: -f1)
        local addr=$(head -n1 "$logfile"|cut -d: -f2)
        local usen=$(head -n1 "$logfile"|cut -d: -f3)
        local nread=$(head -n1 "$logfile"|cut -d: -f4)
        local deviceid="${bus}-${addr}"
        local startat=$(cat "$logfile"|grep startat|cut -d: -f2)
        local endat=$(cat "$logfile"|grep endat|cut -d: -f2)
        local cpu_usage=$(cat "$logfile"|grep statsline|cut -d: -f2|awk '{print(($0+0)/100)}')
        local resident=$(cat "$logfile"|grep statsline|cut -d: -f3|awk '{print(($0+0)*1000)}')
        local infos="${bus},${addr},${usen},${nread},${deviceid},${startat},${endat},${inmem},${cpu_usage},${resident}"
        awk '/Power is/ { print("'${infos}',"$2+0","$3+0","$6+0)}' "$logfile" >> "$csv"
    done
}

zmq () {
    echo "---------- Running zmq experiments ----------"
    info "Disconnecting all ina260..."
    for dev in $(ls /sys/kernel/ina260/)
    do
        dev=$(basename $dev)
        bus=$(echo $dev|cut -d\- -f1)
        addr=$(echo $dev|cut -d\- -f2)
        echo 0x${addr} | sudo tee /sys/bus/i2c/devices/i2c-${bus}/delete_device
    done
    # Setup publisher
    cd ${wai}/ina260-zmq-publisher
    rm -f publisher_*.log
    info "Compiling..."
    make -B
    # Run experiments (add one new ina260 at each loop)
    local n=1
    for dev in $inadev
    do
        info "Run zmq over $n devices for ${zmqduration}s"
        bus=$(echo $dev|cut -d: -f1)
        addr=$(echo $dev|cut -d: -f2)
        [ -z $(ls /sys/kernel/ina260/ |grep "${bus}-.*${addr#0x}") ] && echo ina260 $addr | sudo tee "/sys/bus/i2c/devices/i2c-${bus}/new_device"
        [ -z $(ls /sys/kernel/ina260/ |grep "${bus}-.*${addr#0x}") ] && abort "Cannot connect $dev"
        # Run experiment
        sed "s/^KEY=.*/KEY=usen$n/g" -i config.mk
        make publish &
        sleep ${zmqduration}
        kill -s SIGINT $(cat pid)
        # Wait for all publisher processes to end:
        for pid in $(cat pid)
        do
            while ps -p $pid > /dev/null; do continue; done
        done
        # Done
        n=$(( n + 1 ))
        info "Beaglebone is resting for ${zmqrest}s"
        sleep $zmqrest
    done
    cd ${wai} # Go back to last directory
}

##### Run experiments
# Network benchmark
iperf-run
info "Sleep ${delayiperfpure}s before starting pure-read experiments..."
sleep ${delayiperfpure}
# Pure read
pure-read 1 1    # Do in memory first!
pure-read 0 0    # This way, we are sure in file has no impact
# Sleep
info "Sleep ${delaypurezmq}s before starting zmq experiments..."
sleep ${delaypurezmq}
# ZMQ
zmq