#!/usr/bin/env bash
# Build everything in $BUILD_DIR, run E1-E4, write text results to results/.
#   BUILD_DIR=$(mktemp -d) bash run.sh
# Optional: FASTPFOR_SRC, STREAMVBYTE_SRC (existing checkouts), TIMING_WRAP (prefix for
# timed commands, e.g. a lock), CPU (taskset core, default 1), RUNS (rounds per timing run, default 11), REPS (timing runs, default 3).
set -euo pipefail
HERE=$(cd "$(dirname "$0")" && pwd)
: "${BUILD_DIR:?set BUILD_DIR to a scratch directory}"
RES=${RESULTS:-$HERE/results}
CPU=${CPU:-1}
RUNS=${RUNS:-11}
REPS=${REPS:-3}
read -r -a WRAP <<< "${TIMING_WRAP:-}"
mkdir -p "$BUILD_DIR/data" "$RES"
cd "$BUILD_DIR"

FASTPFOR_SRC=${FASTPFOR_SRC:-$BUILD_DIR/FastPFor-0.5.0}
STREAMVBYTE_SRC=${STREAMVBYTE_SRC:-$BUILD_DIR/streamvbyte-3.0.0}
[ -d "$FASTPFOR_SRC" ] || git clone -q -c advice.detachedHead=false --depth 1 --branch v0.5.0 \
    https://github.com/lemire/FastPFor.git "$FASTPFOR_SRC"
[ -d "$STREAMVBYTE_SRC" ] || git clone -q -c advice.detachedHead=false --depth 1 --branch v3.0.0 \
    https://github.com/lemire/streamvbyte.git "$STREAMVBYTE_SRC"

# Canterbury large corpus (bible.txt, world192.txt)
if [ ! -f large/bible.txt ]; then
    [ -f large.tar.gz ] || curl -sSfL -m 120 -o large.tar.gz https://corpus.canterbury.ac.nz/resources/large.tar.gz
    echo "7df00ff4cb8c9ce4187d9fa4100aa88208a72d9a227e3cd8bab23b71971eaf41  large.tar.gz" | sha256sum -c -
    mkdir -p large && tar -xzf large.tar.gz -C large
fi

echo "== build"
cmake -S "$FASTPFOR_SRC" -B fastpfor -DFASTPFOR_WITH_TEST=OFF -DFASTPFOR_SIMD_MODE=portable \
    -DCMAKE_BUILD_TYPE=Release > cmake.log
cmake --build fastpfor --target FastPFOR -j1 > build.log 2>&1
CFLAGS="-std=c11 -O2 -Wall -Wextra -Werror"
gcc $CFLAGS -o intcodes "$HERE/intcodes.c" -lm
gcc -std=c11 -O1 -g -Wall -Wextra -fsanitize=address,undefined -fno-sanitize-recover=all \
    -o intcodes-san "$HERE/intcodes.c" -lm
gcc $CFLAGS -I"$STREAMVBYTE_SRC/include" -o svb_check "$HERE/svb_check.c" \
    "$STREAMVBYTE_SRC/src/streamvbyte_encode.c" "$STREAMVBYTE_SRC/src/streamvbyte_decode.c"
g++ -std=c++11 -O2 -Wall -Wextra -msse4.2 -I"$FASTPFOR_SRC/headers" -o fp_bits \
    "$HERE/fp_bits.cpp" fastpfor/libFastPFOR.a

echo "== data"
DATASETS="bible world192"
python3 "$HERE/gen_postings.py" text large/bible.txt data/bible.bin
python3 "$HERE/gen_postings.py" text large/world192.txt data/world192.bin
for k in $(seq 1 15); do
    python3 "$HERE/gen_postings.py" bernoulli "$k" "data/bern$k.bin"
    DATASETS="$DATASETS bern$k"
done

echo "== E1 tests"
{
    ./intcodes -T
    for d in $DATASETS; do ./intcodes-san "data/$d.bin" "$d" > /dev/null; done
    echo "ASan/UBSan round trip of all codecs on all datasets: ok"
    ./svb_check
} | tee "$RES/tests.txt"

echo "== E2 sizes"
printf 'dataset\tN\tsubset\tlists\tpostings\tcodec\tbits\tbits_per_int\n' > "$RES/sizes.tsv"
for d in $DATASETS; do
    ./intcodes "data/$d.bin" "$d" >> "$RES/sizes.tsv"
    ./fp_bits "data/$d.bin" "$d" >> "$RES/sizes.tsv"
done

echo "== E3/E4 timing, $REPS independent repetitions"
printf 'rep\tb\thorizontal_ns_per_int\tvertical_sse2_ns_per_int\n' > "$RES/layout_time.tsv"
printf 'rep\tkind\tdataset\tcodec\tmin_ns\tmedian_ns\tmax_ns\n' > "$RES/decode_time.tsv"
: > "$RES/loadavg.txt"
for rep in $(seq 1 "$REPS"); do
    echo "rep $rep before: $(cat /proc/loadavg)" >> "$RES/loadavg.txt"
    "${WRAP[@]}" taskset -c "$CPU" ./intcodes -t | tail -n +2 | sed "s/^/$rep\t/" >> "$RES/layout_time.tsv"
    for d in bible bern4 bern12; do
        "${WRAP[@]}" taskset -c "$CPU" ./fp_bits "data/$d.bin" "$d" -t "$RUNS" | grep '^time' \
            | sed "s/^/$rep\t/" >> "$RES/decode_time.tsv"
    done
done
echo "after: $(cat /proc/loadavg)" >> "$RES/loadavg.txt"

{
    echo "date: $(date -u +%F)"
    echo "kernel: $(uname -r)"
    lscpu | grep -E '^(Model name|CPU\(s\)|Thread|Core|L1d|L2|L3|Hypervisor)'
    gcc --version | head -1
    g++ --version | head -1
    cmake --version | head -1
    python3 --version
    echo "FastPFor: $(git -C "$FASTPFOR_SRC" describe --tags 2>/dev/null || true) $(git -C "$FASTPFOR_SRC" rev-parse HEAD)"
    echo "streamvbyte: $(git -C "$STREAMVBYTE_SRC" describe --tags 2>/dev/null || true) $(git -C "$STREAMVBYTE_SRC" rev-parse HEAD)"
    echo "taskset core: $CPU, runs: $RUNS"
} > "$RES/env.txt"
echo "results in $RES"
