kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

toy_cross_batch.sh (5248B)


      1 #!/usr/bin/env bash
      2 # scripts/toy_cross_batch.sh — fast batched cross-exec of the toy suite for a
      3 # single target arch + opt level. Compiles/links every case natively (fast),
      4 # then runs all executables inside ONE podman container, instead of the
      5 # per-case podman invocation test/toy/run.sh uses. Cuts a full-suite run from
      6 # ~30 min (257 emulated container starts) to a couple of minutes.
      7 #
      8 # Usage: scripts/toy_cross_batch.sh <arch> <opt> [name_substr]
      9 #   arch: rv64 | x64 | aa64        opt: 0 | 1
     10 # Env: KIT (path to kit binary, default build/kit)
     11 #
     12 # Checks only the X path (cross-compile + link + exec rc vs <name>.expected).
     13 # Compile/link failures and nonzero/mismatched rc count as FAIL.
     14 set -u
     15 ROOT="$(cd "$(dirname "$0")/.." && pwd)"
     16 KIT="${KIT:-$ROOT/build/kit}"
     17 ARCH="${1:?arch}"
     18 OPT="${2:?opt}"
     19 FILTER="${3:-}"
     20 CASES="$ROOT/test/toy/cases"
     21 # Under the repo build dir, not /tmp: the podman VM (macOS) shares the repo tree
     22 # but not /tmp, so a /tmp bind-mount fails with "statfs ...: no such file".
     23 WORK="$ROOT/build/toy_cross_batch/$ARCH-O$OPT"
     24 rm -rf "$WORK"; mkdir -p "$WORK"
     25 
     26 # Per-arch image: the three platforms otherwise collide on a shared
     27 # alpine:latest tag (a multi-platform pull overwrites it). Distinct local tags
     28 # (localhost/alpine-{rv64,amd64,arm64}) avoid that; override via RUN_<ARCH>_IMAGE.
     29 case "$ARCH" in
     30   rv64) TRIPLE=riscv64-linux-gnu; PLAT=linux/riscv64; IMAGE="${RUN_RV64_IMAGE:-localhost/alpine-rv64}" ;;
     31   x64)  TRIPLE=x86_64-linux-gnu;  PLAT=linux/amd64;   IMAGE="${RUN_X64_IMAGE:-localhost/alpine-amd64}" ;;
     32   aa64) TRIPLE=aarch64-linux-gnu; PLAT=linux/arm64;   IMAGE="${RUN_AARCH64_IMAGE:-localhost/alpine-arm64}" ;;
     33   *) echo "unknown arch $ARCH"; exit 2 ;;
     34 esac
     35 IMAGE="${IMAGE_OVERRIDE:-$IMAGE}"
     36 
     37 # Build a freestanding _start.o for the target via clang (mirrors run.sh).
     38 START_C="$WORK/start.c"
     39 cat > "$START_C" <<'EOF'
     40 extern int main(void);
     41 __attribute__((noreturn)) static void do_exit(int code) {
     42 #if defined(__aarch64__)
     43   register long x8 __asm__("x8") = 94; register long x0 __asm__("x0") = code;
     44   __asm__ volatile("svc #0" ::"r"(x8), "r"(x0) : "memory");
     45 #elif defined(__x86_64__)
     46   register long rax __asm__("rax") = 231; register long rdi __asm__("rdi") = code;
     47   __asm__ volatile("syscall" ::"r"(rax), "r"(rdi) : "memory");
     48 #elif defined(__riscv) && __riscv_xlen == 64
     49   register long a7 __asm__("a7") = 94; register long a0 __asm__("a0") = code;
     50   __asm__ volatile("ecall" ::"r"(a7), "r"(a0) : "memory");
     51 #endif
     52   __builtin_unreachable();
     53 }
     54 #if defined(__x86_64__)
     55 __attribute__((force_align_arg_pointer))
     56 #endif
     57 void _start(void) { do_exit(main()); }
     58 EOF
     59 if ! clang --target="$TRIPLE" -O1 -ffreestanding -fno-stack-protector -fno-PIC \
     60      -fno-pie -c "$START_C" -o "$WORK/start.o" 2>"$WORK/start.err"; then
     61   echo "FATAL: could not build start.o for $TRIPLE"; cat "$WORK/start.err"; exit 2
     62 fi
     63 
     64 PASS=0; FAIL=0; SKIP=0; FAILED=()
     65 RUNLIST="$WORK/runlist.txt"; : > "$RUNLIST"
     66 declare -A EXPECT
     67 
     68 for src in "$CASES"/*.toy; do
     69   name="$(basename "$src" .toy)"
     70   [ -n "$FILTER" ] && [[ "$name" != *"$FILTER"* ]] && continue
     71   # asmnop is aa64-specific before toy asm selectors.
     72   if [ "$ARCH" != "aa64" ] && grep -q 'asmnop' "$src"; then
     73     SKIP=$((SKIP+1)); continue
     74   fi
     75   exp=0; [ -f "${src%.toy}.expected" ] && exp="$(tr -d '[:space:]' < "${src%.toy}.expected")"
     76   EXPECT[$name]=$exp
     77   if ! "$KIT" cc "-O$OPT" -target "$TRIPLE" -c "$src" -o "$WORK/$name.o" \
     78        >"$WORK/$name.cc.out" 2>"$WORK/$name.cc.err"; then
     79     FAIL=$((FAIL+1)); FAILED+=("$name [cc] $(head -1 "$WORK/$name.cc.err")"); continue
     80   fi
     81   if [ -s "$WORK/$name.cc.err" ]; then
     82     FAIL=$((FAIL+1)); FAILED+=("$name [cc-stderr] $(head -1 "$WORK/$name.cc.err")"); continue
     83   fi
     84   if ! "$KIT" ld "$WORK/$name.o" "$WORK/start.o" -o "$WORK/$name.exe" \
     85        >"$WORK/$name.ld.out" 2>"$WORK/$name.ld.err"; then
     86     FAIL=$((FAIL+1)); FAILED+=("$name [ld] $(head -1 "$WORK/$name.ld.err")"); continue
     87   fi
     88   chmod +x "$WORK/$name.exe" 2>/dev/null || true
     89   echo "$name" >> "$RUNLIST"
     90 done
     91 
     92 # Single batched container run: execute every linked exe, print "name rc".
     93 # The in-container loop is written to a file (bind-mounted via $WORK) rather than
     94 # inlined through nested sh/bash quoting, which is brittle and shell-dependent.
     95 RESULTS="$WORK/results.txt"
     96 INRUN="$WORK/run_in_container.sh"
     97 cat > "$INRUN" <<EOF
     98 cd "$WORK" || exit 2
     99 while read n; do
    100   "./\$n.exe" >/dev/null 2>"$WORK/\$n.run.err"; echo "\$n \$?"
    101 done < "$RUNLIST"
    102 EOF
    103 if [ -s "$RUNLIST" ]; then
    104   podman run --rm --pull=never --platform "$PLAT" --net=none \
    105     -v "$WORK:$WORK" -w "$WORK" "$IMAGE" sh "$INRUN" \
    106     > "$RESULTS" 2>"$WORK/podman.err" || {
    107         echo "FATAL: podman batch run failed"; cat "$WORK/podman.err"; exit 2; }
    108 fi
    109 
    110 while read -r name rc; do
    111   exp=${EXPECT[$name]:-0}; exp=$((exp & 255))
    112   if [ "$rc" -eq "$exp" ] && [ ! -s "$WORK/$name.run.err" ]; then
    113     PASS=$((PASS+1))
    114   else
    115     FAIL=$((FAIL+1))
    116     msg="rc=$rc want=$exp"; [ -s "$WORK/$name.run.err" ] && msg="$msg stderr=$(head -1 "$WORK/$name.run.err")"
    117     FAILED+=("$name [run] $msg")
    118   fi
    119 done < "$RESULTS"
    120 
    121 echo "==== $ARCH -O$OPT : $PASS pass, $FAIL fail, $SKIP skip ===="
    122 if [ "${#FAILED[@]}" -gt 0 ]; then
    123   printf '%s\n' "${FAILED[@]}" | sort
    124 fi
    125 [ "$FAIL" -eq 0 ]