commit c562293046d7bf431615d75bb41393db83b99197
parent 5cb0213fcda79c07c71fe59fa9aa10e792d32c67
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sat, 9 May 2026 12:18:43 -0700
test-link: add filters, per-path timing; fix slow podman exec path
- ./run.sh [name_filter] [paths] (or CFREE_TEST_FILTER/CFREE_TEST_PATHS)
to scope a run to one case and/or a subset of R/E/J.
- Per-case ms timings on PASS/FAIL lines plus a totals line.
- Drop --platform linux/arm64 from podman run on arm64 hosts: the flag
triggers a registry manifest lookup (~30s) even when the local image
is already arm64. Cuts path E from ~32s to ~0.5s per case.
Diffstat:
| M | test/link/run.sh | | | 65 | ++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
1 file changed, 48 insertions(+), 17 deletions(-)
diff --git a/test/link/run.sh b/test/link/run.sh
@@ -26,6 +26,12 @@
# gc_absent — one symbol per line; jit-runner verifies each is absent
# after --gc-sections (implies linker_flags contains that flag)
# archive_b — package b.o into b.a; content "demand" or "whole"
+#
+# Filtering:
+# ./run.sh [name_filter] [paths]
+# name_filter substring match against case name (e.g. "02", "rodata")
+# paths subset of "REJ" (default "REJ")
+# Equivalent env vars: CFREE_TEST_FILTER, CFREE_TEST_PATHS.
set -u
@@ -44,6 +50,17 @@ CC="${CC:-cc}"
CFREE_CFLAGS="-I$ROOT/include"
ALLOW_SKIP="${CFREE_TEST_ALLOW_SKIP:-0}"
+# Filters (env vars or positional args; args win):
+# $1 / CFREE_TEST_FILTER — substring match against case name (e.g. "02" or "rodata")
+# $2 / CFREE_TEST_PATHS — subset of "REJ" (default "REJ"); selects which paths run
+FILTER="${1:-${CFREE_TEST_FILTER:-}}"
+PATHS="${2:-${CFREE_TEST_PATHS:-REJ}}"
+case "$PATHS" in *R*) RUN_R=1;; *) RUN_R=0;; esac
+case "$PATHS" in *E*) RUN_E=1;; *) RUN_E=0;; esac
+case "$PATHS" in *J*) RUN_J=1;; *) RUN_J=0;; esac
+T_R=0; T_E=0; T_J=0 # accumulated wall-clock seconds per path
+now_ms() { python3 -c 'import time;print(int(time.time()*1000))'; }
+
mkdir -p "$BUILD_DIR"
mkdir -p "$BUILD_DIR/link"
@@ -96,9 +113,13 @@ run_aarch64() {
"$QEMU_BIN" "$exe" >"$out" 2>"$err"; RUN_RC=$?; return
fi
if [ $have_podman -eq 1 ]; then
- local dir base
+ local dir base platform_flag=()
dir="$(cd "$(dirname "$exe")" && pwd)"; base="$(basename "$exe")"
- podman run --rm --platform linux/arm64 --net=none \
+ # `--platform linux/arm64` triggers a registry manifest lookup (~30s)
+ # even when the local image is already arm64. Only pass it on hosts
+ # where the podman machine isn't natively arm64.
+ [ $is_aarch64 -eq 0 ] && platform_flag=(--platform linux/arm64)
+ podman run --rm "${platform_flag[@]}" --net=none \
-v "$dir":/work:Z -w /work "$RUN_AARCH64_IMAGE" "./$base" >"$out" 2>"$err"
RUN_RC=$?; return
fi
@@ -145,6 +166,7 @@ printf 'Running cases...\n'
for case_dir in "$TEST_DIR/cases"/*/; do
[ -d "$case_dir" ] || continue
name="$(basename "$case_dir")"
+ [ -n "$FILTER" ] && [[ "$name" != *"$FILTER"* ]] && continue
work="$BUILD_DIR/link/$name"
mkdir -p "$work"
@@ -231,8 +253,9 @@ for case_dir in "$TEST_DIR/cases"/*/; do
done
# ---- Path R: roundtrip --------------------------------------------------
- if [ $jit_only -eq 0 ]; then
+ if [ $jit_only -eq 0 ] && [ $RUN_R -eq 1 ]; then
if [ $have_roundtrip -eq 1 ] && [ $have_readelf -eq 1 ] && [ $have_python3 -eq 1 ]; then
+ t0=$(now_ms)
r_ok=1
for obj in "${rt_obj_files[@]}"; do
base="$(basename "$obj" .o)"
@@ -250,7 +273,8 @@ for case_dir in "$TEST_DIR/cases"/*/; do
r_ok=0; break
fi
done
- if [ $r_ok -eq 1 ]; then note_pass "$name/R"
+ dt=$(( $(now_ms) - t0 )); T_R=$(( T_R + dt ))
+ if [ $r_ok -eq 1 ]; then note_pass "$name/R (${dt}ms)"
else note_fail "$name/R"; fi
else
note_skip "$name/R" "missing roundtrip/readelf/python3"
@@ -258,7 +282,8 @@ for case_dir in "$TEST_DIR/cases"/*/; do
fi
# ---- Path E: exec -------------------------------------------------------
- if [ $jit_only -eq 0 ] && [ $have_exe_runner -eq 1 ]; then
+ if [ $jit_only -eq 0 ] && [ $RUN_E -eq 1 ] && [ $have_exe_runner -eq 1 ]; then
+ t0=$(now_ms)
# Compile start.o
start_obj="$work/start.o"
clang $CLANG_TARGET -O1 -ffreestanding -fno-stack-protector \
@@ -270,22 +295,25 @@ for case_dir in "$TEST_DIR/cases"/*/; do
"${link_obj_files[@]}" "$start_obj" "${link_arc_flags[@]}")
if ! "${link_cmd[@]}" >"$work/exec_link.out" 2>"$work/exec_link.err"; then
- note_fail "$name/E (link failed)"
+ dt=$(( $(now_ms) - t0 )); T_E=$(( T_E + dt ))
+ note_fail "$name/E (link failed, ${dt}ms)"
elif [ $have_runner -eq 1 ]; then
run_aarch64 "$exe" "$work/exec.out" "$work/exec.err"
- if [ "$RUN_RC" -eq "$expected" ]; then note_pass "$name/E"
- else note_fail "$name/E (expected $expected, got $RUN_RC)"; fi
+ dt=$(( $(now_ms) - t0 )); T_E=$(( T_E + dt ))
+ if [ "$RUN_RC" -eq "$expected" ]; then note_pass "$name/E (${dt}ms)"
+ else note_fail "$name/E (expected $expected, got $RUN_RC, ${dt}ms)"; fi
else
note_skip "$name/E" "no runner (qemu/podman)"
fi
else
- if [ $jit_only -eq 0 ]; then
+ if [ $jit_only -eq 0 ] && [ $RUN_E -eq 1 ]; then
note_skip "$name/E" "no link-exe-runner"
fi
fi
# ---- Path J: JIT --------------------------------------------------------
- if [ $have_jit_runner -eq 1 ]; then
+ if [ $RUN_J -eq 1 ] && [ $have_jit_runner -eq 1 ]; then
+ t0=$(now_ms)
jit_cmd=("$JIT_RUNNER" "${extra_flags[@]}")
[ $use_resolver -eq 1 ] && jit_cmd+=(--use-resolver)
jit_cmd+=("${link_obj_files[@]}" "${link_arc_flags[@]}")
@@ -309,9 +337,10 @@ for case_dir in "$TEST_DIR/cases"/*/; do
fi
done
- if [ "$j_rc" -eq "$expected" ]; then note_pass "$name/J"
- else note_fail "$name/J (expected $expected, got $j_rc)"; fi
- else
+ dt=$(( $(now_ms) - t0 )); T_J=$(( T_J + dt ))
+ if [ "$j_rc" -eq "$expected" ]; then note_pass "$name/J (${dt}ms)"
+ else note_fail "$name/J (expected $expected, got $j_rc, ${dt}ms)"; fi
+ elif [ $RUN_J -eq 1 ]; then
note_skip "$name/J" "no jit-runner (not aarch64 host or build failed)"
fi
@@ -326,6 +355,7 @@ done
for case_dir in "$TEST_DIR/bad"/*/; do
[ -d "$case_dir" ] || continue
name="bad/$(basename "$case_dir")"
+ [ -n "$FILTER" ] && [[ "$name" != *"$FILTER"* ]] && continue
work="$BUILD_DIR/link/$name"
mkdir -p "$work"
@@ -359,7 +389,7 @@ for case_dir in "$TEST_DIR/bad"/*/; do
fi
# Path E
- if [ $have_exe_runner -eq 1 ]; then
+ if [ $RUN_E -eq 1 ] && [ $have_exe_runner -eq 1 ]; then
start_obj="$work/start.o"
clang $CLANG_TARGET -O1 -ffreestanding -fno-stack-protector \
-fno-PIC -fno-pie \
@@ -379,12 +409,12 @@ for case_dir in "$TEST_DIR/bad"/*/; do
note_pass "$name/E"
fi
fi
- else
+ elif [ $RUN_E -eq 1 ]; then
note_skip "$name/E" "no link-exe-runner"
fi
# Path J
- if [ $have_jit_runner -eq 1 ]; then
+ if [ $RUN_J -eq 1 ] && [ $have_jit_runner -eq 1 ]; then
if "$JIT_RUNNER" "${obj_files[@]}" >"$work/jit.out" 2>"$work/jit.err"; then
note_fail "$name/J (jit-runner succeeded; expected non-zero exit)"
else
@@ -398,7 +428,7 @@ for case_dir in "$TEST_DIR/bad"/*/; do
note_pass "$name/J"
fi
fi
- else
+ elif [ $RUN_J -eq 1 ]; then
note_skip "$name/J" "no jit-runner (not aarch64 host or build failed)"
fi
done
@@ -407,6 +437,7 @@ done
printf '\n'
printf 'Results: %s pass, %s fail, %s skip\n' "$PASS" "$FAIL" "$SKIP"
+printf 'Time: R=%dms E=%dms J=%dms\n' "$T_R" "$T_E" "$T_J"
if [ ${#FAIL_NAMES[@]} -gt 0 ]; then
printf 'Failed:\n'