commit 306b2919c7c7aea6a5641295b79bb3a9df6b16ba
parent f6b905f93ad5d469c4983625fbe7f28aaa64b906
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 17:39:44 -0700
Speed up tier1 timing diagnostics
Diffstat:
9 files changed, 425 insertions(+), 56 deletions(-)
diff --git a/mk/test.mk b/mk/test.mk
@@ -281,7 +281,7 @@ test-t1-link-jit: bin
test-t1-cross: bin
@$(T1_LOG) cross env KIT=$(abspath $(BIN)) test/tier1/cross/run.sh
-test-t1-rt:
+test-t1-rt: bin
@$(T1_LOG) rt test/tier1/system/runtime-headers.sh
test-t1-debug:
diff --git a/test/driver/run.sh b/test/driver/run.sh
@@ -26,6 +26,41 @@ KIT_KIT_DIR="$repo_root/test/lib"
. "$repo_root/test/lib/kit_sh_kit.sh"
kit_report_init
+driver_now_ms() {
+ perl -MTime::HiRes=time -e 'printf "%.0f\n", time() * 1000' 2>/dev/null ||
+ printf '%s000\n' "$(date +%s 2>/dev/null || printf '0')"
+}
+
+driver_section_id=
+driver_section_start=0
+
+driver_slow_timing_enabled() {
+ case "${KIT_TIER1_SLOW_TIMING:-0}" in
+ 1|yes|true|on) return 0 ;;
+ *) return 1 ;;
+ esac
+}
+
+driver_section_done() {
+ [ -n "$driver_section_id" ] || return 0
+ if ! driver_slow_timing_enabled; then
+ driver_section_id=
+ return 0
+ fi
+ driver_section_end=$(driver_now_ms)
+ driver_section_ms=$((driver_section_end - driver_section_start))
+ [ "$driver_section_ms" -lt 0 ] && driver_section_ms=0
+ kit_time "$driver_section_id" "$driver_section_ms"
+ driver_section_id=
+}
+
+driver_section() {
+ driver_slow_timing_enabled || return 0
+ driver_section_done
+ driver_section_id=$1
+ driver_section_start=$(driver_now_ms)
+}
+
cat > "$work/main.c" <<'SRC'
int main(void) { return 0; }
int _start(void) { return 0; }
@@ -35,6 +70,8 @@ cat > "$work/other.c" <<'SRC'
int other(void) { return 0; }
SRC
+driver_section cc_ld_modes
+
# ---- executable permission bits (cc/ld) ----
if (umask 077; "$KIT" cc "$work/main.c" -o "$work/cc-exe") \
> "$work/cc.out" 2> "$work/cc.err"; then
@@ -291,6 +328,8 @@ else
fi
# ---- runtime auto-build + link via nm (aarch64) ----
+driver_section runtime_link
+
mkdir -p "$work/rt-support/rt"
cp -R "$repo_root/rt/include" "$work/rt-support/rt/include"
cp -R "$repo_root/rt/lib" "$work/rt-support/rt/lib"
@@ -441,6 +480,8 @@ else
fi
# ---- ld PIE without dynamic deps has no INTERP/DYNAMIC program headers ----
+driver_section pie_macho_darwin
+
cat > "$work/ld-static-pie.c" <<'SRC'
void _start(void) { for (;;) {} }
SRC
@@ -637,6 +678,8 @@ SRC
fi
# ---- run: JIT compile a source + archive on demand, exit status is the result ----
+driver_section run_hosted
+
cat > "$work/run-main.c" <<'SRC'
int add42(int);
int main(void) { return add42(0); }
@@ -875,6 +918,8 @@ else
fi
# ---- rv64 cross-target end-to-end (as, cc, ld, objdump) ----
+driver_section rv64_check_tools
+
# Exercises the rv64 lane of each tool the toolchain claims to support.
# Cross-compile-only; no qemu/native exec required.
cat > "$work/rv64-asm.S" <<'SRC'
@@ -1222,6 +1267,8 @@ else
fi
# ---- install: symlink the kit tools into a dir ----
+driver_section install_backtrace_autovar
+
# Default set: toolchain + standard-named byte utils, each link -> the binary.
inst_dir="$work/inst"
run_ok "install-default" "$KIT" install "$inst_dir"
@@ -1373,5 +1420,6 @@ else
"host cannot natively run kit cc output"
fi
+driver_section_done
kit_summary driver-cc
kit_exit
diff --git a/test/tier1/cross/run.sh b/test/tier1/cross/run.sh
@@ -8,10 +8,12 @@ CASES="$ROOT/test/cross/cases"
KITCHEN="$ROOT/test/tier1/kitchen/cross"
WORK="$ROOT/build/test/tier1/cross"
SELECTOR="${T1_CROSS_TARGETS:-all}"
+PARALLEL_DIR="$WORK/.parallel"
-mkdir -p "$WORK"
+mkdir -p "$WORK" "$PARALLEL_DIR"
. "$ROOT/test/lib/kit_sh_report.sh"
+. "$ROOT/test/tier1/timing.sh"
kit_report_init
KIT_SKIP_IS_FAILURE=1
@@ -60,10 +62,24 @@ mode_flag() {
run_cmd() {
local label="$1" log="$2"
shift 2
+ local start_ms dur_ms
+ start_ms=$(t1_now_ms)
if "$@" >"$log" 2>&1; then
+ if t1_slow_timing_enabled; then
+ dur_ms=$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")
+ printf ' ok: %s (%sms)\n' "$label" "$dur_ms"
+ else
+ printf ' ok: %s\n' "$label"
+ fi
return 0
fi
kit_fail "$label" "see $log"
+ if t1_slow_timing_enabled; then
+ dur_ms=$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")
+ printf ' failed: %s (%sms)\n' "$label" "$dur_ms"
+ else
+ printf ' failed: %s\n' "$label"
+ fi
return 1
}
@@ -251,29 +267,70 @@ freestanding_lane() {
if [ -s "$exe" ]; then kit_pass "$token"; else kit_fail "$token" "linked artifact missing"; fi
}
+enqueue_lane() {
+ local label="$1" id out
+ shift
+ id=$(t1_step_id "$label")
+ out="$PARALLEL_DIR/$id.out"
+ printf '%s\t%s\n' "$label" "$out" >> "$PARALLEL_DIR/order"
+ t1_parallel_wait_for_slot "$T1_CROSS_JOBS"
+ "$@" > "$out" 2>&1 &
+}
+
+replay_and_exit() {
+ local combined="$PARALLEL_DIR/combined.out" pass fail skip failures skips
+ : > "$combined"
+ while IFS="$(printf '\t')" read -r label out; do
+ [ -n "$label" ] || continue
+ cat "$out"
+ cat "$out" >> "$combined"
+ done < "$PARALLEL_DIR/order"
+
+ pass=$(awk '/^[[:space:]]+PASS[[:space:]]/{n++} END{print n+0}' "$combined")
+ fail=$(awk '/^[[:space:]]+FAIL[[:space:]]/{n++} END{print n+0}' "$combined")
+ skip=$(awk '/^[[:space:]]+SKIP[[:space:]]/{n++} END{print n+0}' "$combined")
+ failures=$(awk '/^[[:space:]]+FAIL[[:space:]]/{printf " %s", $2}' "$combined")
+ skips=$(awk '/^[[:space:]]+SKIP[[:space:]]/{printf " %s", $2}' "$combined")
+
+ [ -n "$failures" ] && printf '\ntest-t1-cross: failures:%s\n' "$failures"
+ [ -n "$skips" ] && printf 'test-t1-cross: skipped:%s\n' "$skips"
+ printf '\ntest-t1-cross: %d pass, %d fail, %d skip\n' "$pass" "$fail" "$skip"
+
+ [ "$fail" -gt 0 ] && exit 1
+ if [ "${KIT_SKIP_IS_FAILURE:-0}" = "1" ] && [ "$skip" -gt 0 ] &&
+ [ "${KIT_TEST_ALLOW_SKIP:-0}" != "1" ]; then
+ exit 1
+ fi
+ exit 0
+}
+
+rm -f "$PARALLEL_DIR/order"
+: > "$PARALLEL_DIR/order"
+T1_CROSS_JOBS=$(t1_parallel_jobs) || exit $?
+
for arch in aa64 x64 rv64; do
- hosted_lane "linux-glibc-$arch" default
- linux_shared_lane "linux-glibc-$arch"
- hosted_lane "linux-musl-$arch" static
- hosted_lane "linux-musl-$arch" dynamic
- linux_shared_lane "linux-musl-$arch"
- hosted_lane "freebsd-$arch" static
+ enqueue_lane "linux-glibc-$arch" hosted_lane "linux-glibc-$arch" default
+ enqueue_lane "linux-glibc-$arch:shared" linux_shared_lane "linux-glibc-$arch"
+ enqueue_lane "linux-musl-$arch:static" hosted_lane "linux-musl-$arch" static
+ enqueue_lane "linux-musl-$arch:dynamic" hosted_lane "linux-musl-$arch" dynamic
+ enqueue_lane "linux-musl-$arch:shared" linux_shared_lane "linux-musl-$arch"
+ enqueue_lane "freebsd-$arch:static" hosted_lane "freebsd-$arch" static
done
for arch in aa64 x64; do
- hosted_lane "windows-$arch" default
- hosted_lane "macos-$arch" default
+ enqueue_lane "windows-$arch" hosted_lane "windows-$arch" default
+ enqueue_lane "macos-$arch" hosted_lane "macos-$arch" default
done
-android_lane
+enqueue_lane android-aa64 android_lane
-apple_lane ios-aa64 arm64-apple-ios iphoneos
-apple_lane ios-sim-aa64 arm64-apple-ios-simulator iphonesimulator
-apple_lane ios-sim-x64 x86_64-apple-ios-simulator iphonesimulator
+enqueue_lane ios-aa64 apple_lane ios-aa64 arm64-apple-ios iphoneos
+enqueue_lane ios-sim-aa64 apple_lane ios-sim-aa64 arm64-apple-ios-simulator iphonesimulator
+enqueue_lane ios-sim-x64 apple_lane ios-sim-x64 x86_64-apple-ios-simulator iphonesimulator
for arch in aa64 x64 rv64 rv32 arm32; do
- freestanding_lane "$arch"
+ enqueue_lane "freestanding-$arch" freestanding_lane "$arch"
done
-kit_summary test-t1-cross
-kit_exit
+wait || true
+replay_and_exit
diff --git a/test/tier1/run_logged.sh b/test/tier1/run_logged.sh
@@ -14,17 +14,66 @@ log_dir="$root/build/test/tier1/logs"
log="$log_dir/$label.log"
mkdir -p "$log_dir"
+. "$root/test/tier1/timing.sh"
+
+print_child_timings() {
+ max=${T1_TIMING_LINES:-8}
+ timings=$(
+ awk '
+ /^tier1\/[^:]+: / {
+ cur = $0
+ sub(/^tier1\/[^:]+: /, "", cur)
+ next
+ }
+ /^[[:space:]]+ok: / {
+ if (match($0, /\(([0-9]+)ms\)/)) {
+ ms = substr($0, RSTART + 1, RLENGTH - 4)
+ name = cur
+ if ($0 ~ /^[[:space:]]+ok: [^\/]/) {
+ name = $0
+ sub(/^[[:space:]]+ok: /, "", name)
+ sub(/[[:space:]]+\([0-9]+ms\).*$/, "", name)
+ }
+ if (name != "") printf "%s\t%s\n", ms, name
+ }
+ }
+ /^[^:]+: time / {
+ for (i = 3; i <= NF; ++i) {
+ split($i, kv, "=")
+ if (kv[1] != "" && kv[2] ~ /^[0-9]+ms$/) {
+ sub(/ms$/, "", kv[2])
+ printf "%s\t%s\n", kv[2], kv[1]
+ }
+ }
+ }
+ ' "$log" | sort -nr | head -n "$max"
+ )
+ [ -n "$timings" ] || return 0
+ printf ' slow steps: '
+ printf '%s\n' "$timings" |
+ awk -F '\t' '{ printf "%s%s=%sms", sep, $2, $1; sep=", " } END { printf "\n" }'
+}
+
+start_ms=$(t1_now_ms)
"$@" >"$log" 2>&1
rc=$?
+dur_ms=$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")
+
if [ "$rc" -ne 0 ]; then
- printf 'T1 %s failed; tail of %s:\n' "$label" "$log" >&2
+ printf 'T1 %s failed after %sms; tail of %s:\n' "$label" "$dur_ms" "$log" >&2
tail -100 "$log" >&2 || true
exit "$rc"
fi
skips="$(sed -n 's/^[^:][^:]*: skipped: //p' "$log" | tr '\n' ' ' | sed -e 's/[[:space:]][[:space:]]*/ /g' -e 's/^ //' -e 's/ $//')"
if [ -n "$skips" ]; then
nskip="$(printf '%s\n' "$skips" | wc -w | tr -d '[:space:]')"
- printf 'T1 %-18s OK (%s skip: %s)\n' "$label" "$nskip" "$skips"
+ printf 'T1 %-18s OK %sms (%s skip: %s)\n' "$label" "$dur_ms" "$nskip" "$skips"
+ if t1_slow_timing_enabled; then
+ print_child_timings
+ fi
exit 0
fi
-printf 'T1 %-18s OK\n' "$label"
+printf 'T1 %-18s OK %sms\n' "$label" "$dur_ms"
+if t1_slow_timing_enabled; then
+ print_child_timings
+fi
diff --git a/test/tier1/system/debug-dwarf.sh b/test/tier1/system/debug-dwarf.sh
@@ -9,18 +9,30 @@ manifest="$repo_root/test/tier1/manifests/system/debug-dwarf.txt"
log_dir="${KIT_TIER1_LOG_DIR:-$repo_root/build/test/tier1/logs/system/debug-dwarf}"
mkdir -p "$log_dir"
+. "$script_dir/../timing.sh"
run_step() {
name=$1
shift
log="$log_dir/$name.log"
+ start_ms=$(t1_now_ms)
printf 'tier1/debug-dwarf: %s\n' "$name"
- if "$@" > "$log" 2>&1; then
- printf ' ok: %s\n' "$log"
+ "$@" > "$log" 2>&1
+ rc=$?
+ if [ "$rc" -eq 0 ]; then
+ if t1_slow_timing_enabled; then
+ printf ' ok: %s (%sms)\n' "$log" "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")"
+ else
+ printf ' ok: %s\n' "$log"
+ fi
return 0
fi
- rc=$?
- printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ if t1_slow_timing_enabled; then
+ printf ' FAIL: %s (exit %s, %sms)\n' "$log" "$rc" \
+ "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")" >&2
+ else
+ printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ fi
tail -n 80 "$log" >&2
return "$rc"
}
@@ -31,6 +43,7 @@ run_objdump_dwarf() {
actual="$log_dir/$name.actual"
expected="$repo_root/test/objdump/dwarf/cases/01-dwarf-all.expected"
case_sh="$repo_root/test/objdump/dwarf/cases/01-dwarf-all.sh"
+ start_ms=$(t1_now_ms)
printf 'tier1/debug-dwarf: %s\n' "$name"
(
@@ -43,10 +56,19 @@ run_objdump_dwarf() {
rc=$?
fi
if [ "$rc" -eq 0 ]; then
- printf ' ok: %s\n' "$log"
+ if t1_slow_timing_enabled; then
+ printf ' ok: %s (%sms)\n' "$log" "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")"
+ else
+ printf ' ok: %s\n' "$log"
+ fi
return 0
fi
- printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ if t1_slow_timing_enabled; then
+ printf ' FAIL: %s (exit %s, %sms)\n' "$log" "$rc" \
+ "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")" >&2
+ else
+ printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ fi
tail -n 80 "$log" >&2
return "$rc"
}
@@ -57,33 +79,73 @@ if [ ! -f "$manifest" ]; then
fi
count=0
-while IFS= read -r step || [ -n "$step" ]; do
- step=${step%%#*}
- step=$(printf '%s' "$step" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- [ -n "$step" ] || continue
- count=$((count + 1))
+order="$log_dir/.order.$$"
+: > "$order"
+jobs=$(t1_parallel_jobs) || exit $?
+
+run_manifest_step() {
+ step=$1
case "$step" in
- make:bin)
- run_step bin make -C "$repo_root" bin || exit $? ;;
make:test-dwarf)
- run_step test-dwarf make -C "$repo_root" test-dwarf || exit $? ;;
+ run_step test-dwarf make -C "$repo_root" test-dwarf ;;
make:test-debug)
- run_step test-debug make -C "$repo_root" test-debug || exit $? ;;
+ run_step test-debug make -C "$repo_root" test-debug ;;
driver:objdump-dwarf/01-dwarf-all)
- run_objdump_dwarf || exit $? ;;
+ run_objdump_dwarf ;;
driver:dbg/repl-help)
run_step dbg-repl-help env KIT="$repo_root/build/kit" DBG_CASE=repl-help \
- sh "$repo_root/test/dbg/run.sh" || exit $? ;;
+ sh "$repo_root/test/dbg/run.sh" ;;
driver:addr2line-symbolize)
- run_step addr2line-symbolize make -C "$repo_root" test-rt-backtrace \
- || exit $? ;;
+ run_step addr2line-symbolize make -C "$repo_root" test-rt-backtrace ;;
*)
printf 'tier1/debug-dwarf: unknown manifest step: %s\n' "$step" >&2
- exit 2 ;;
+ return 2 ;;
+ esac
+}
+
+start_step() {
+ step=$1
+ id=$(t1_step_id "$step")
+ out="$log_dir/.step-$id.out"
+ status="$log_dir/.step-$id.status"
+ printf '%s\t%s\t%s\n' "$id" "$out" "$status" >> "$order"
+ t1_parallel_wait_for_slot "$jobs"
+ (
+ if run_manifest_step "$step" > "$out" 2>&1; then
+ printf '0\n' > "$status"
+ else
+ printf '%s\n' "$?" > "$status"
+ fi
+ ) &
+}
+
+while IFS= read -r step || [ -n "$step" ]; do
+ step=${step%%#*}
+ step=$(printf '%s' "$step" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ [ -n "$step" ] || continue
+ count=$((count + 1))
+ case "$step" in
+ make:bin)
+ run_step bin make -C "$repo_root" bin || exit $? ;;
+ *)
+ start_step "$step" ;;
esac
done < "$manifest"
+wait || true
+
if [ "$count" -eq 0 ]; then
printf 'tier1/debug-dwarf: manifest has no runnable steps: %s\n' "$manifest" >&2
exit 2
fi
+
+rc=0
+while IFS="$(printf '\t')" read -r id out status; do
+ [ -n "$id" ] || continue
+ cat "$out"
+ step_rc=$(cat "$status" 2>/dev/null || printf '1\n')
+ if [ "$step_rc" -ne 0 ] && [ "$rc" -eq 0 ]; then
+ rc=$step_rc
+ fi
+done < "$order"
+exit "$rc"
diff --git a/test/tier1/system/dist.sh b/test/tier1/system/dist.sh
@@ -9,18 +9,30 @@ manifest="$repo_root/test/tier1/manifests/system/dist.txt"
log_dir="${KIT_TIER1_LOG_DIR:-$repo_root/build/test/tier1/logs/system/dist}"
mkdir -p "$log_dir"
+. "$script_dir/../timing.sh"
run_step() {
name=$1
shift
log="$log_dir/$name.log"
+ start_ms=$(t1_now_ms)
printf 'tier1/dist: %s\n' "$name"
- if "$@" > "$log" 2>&1; then
- printf ' ok: %s\n' "$log"
+ "$@" > "$log" 2>&1
+ rc=$?
+ if [ "$rc" -eq 0 ]; then
+ if t1_slow_timing_enabled; then
+ printf ' ok: %s (%sms)\n' "$log" "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")"
+ else
+ printf ' ok: %s\n' "$log"
+ fi
return 0
fi
- rc=$?
- printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ if t1_slow_timing_enabled; then
+ printf ' FAIL: %s (exit %s, %sms)\n' "$log" "$rc" \
+ "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")" >&2
+ else
+ printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ fi
tail -n 80 "$log" >&2
return "$rc"
}
@@ -31,15 +43,48 @@ if [ ! -f "$manifest" ]; then
fi
count=0
+order="$log_dir/.order.$$"
+: > "$order"
+jobs=$(t1_parallel_jobs) || exit $?
+
+start_step() {
+ target=$1
+ id=$(t1_step_id "$target")
+ out="$log_dir/.step-$id.out"
+ status="$log_dir/.step-$id.status"
+ printf '%s\t%s\t%s\n' "$id" "$out" "$status" >> "$order"
+ t1_parallel_wait_for_slot "$jobs"
+ (
+ if run_step "$target" make -C "$repo_root" "$target" > "$out" 2>&1; then
+ printf '0\n' > "$status"
+ else
+ printf '%s\n' "$?" > "$status"
+ fi
+ ) &
+}
+
while IFS= read -r target || [ -n "$target" ]; do
target=${target%%#*}
target=$(printf '%s' "$target" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -n "$target" ] || continue
count=$((count + 1))
- run_step "$target" make -C "$repo_root" "$target" || exit $?
+ start_step "$target"
done < "$manifest"
+wait || true
+
if [ "$count" -eq 0 ]; then
printf 'tier1/dist: manifest has no runnable targets: %s\n' "$manifest" >&2
exit 2
fi
+
+rc=0
+while IFS="$(printf '\t')" read -r id out status; do
+ [ -n "$id" ] || continue
+ cat "$out"
+ step_rc=$(cat "$status" 2>/dev/null || printf '1\n')
+ if [ "$step_rc" -ne 0 ] && [ "$rc" -eq 0 ]; then
+ rc=$step_rc
+ fi
+done < "$order"
+exit "$rc"
diff --git a/test/tier1/system/runtime-headers.sh b/test/tier1/system/runtime-headers.sh
@@ -7,6 +7,7 @@ script_dir=$(cd "$(dirname "$0")" && pwd)
repo_root=$(cd "$script_dir/../../.." && pwd)
manifest="$repo_root/test/tier1/manifests/system/runtime-headers.txt"
log_dir="${KIT_TIER1_LOG_DIR:-$repo_root/build/test/tier1/logs/system/runtime-headers}"
+KIT="${KIT:-$repo_root/build/kit}"
mkdir -p "$log_dir"
@@ -15,11 +16,12 @@ run_step() {
shift
log="$log_dir/$name.log"
printf 'tier1/runtime-headers: %s\n' "$name"
- if "$@" > "$log" 2>&1; then
+ "$@" > "$log" 2>&1
+ rc=$?
+ if [ "$rc" -eq 0 ]; then
printf ' ok: %s\n' "$log"
return 0
fi
- rc=$?
printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
tail -n 80 "$log" >&2
return "$rc"
@@ -36,7 +38,11 @@ while IFS= read -r target || [ -n "$target" ]; do
target=${target%%#*}
target=$(printf '%s' "$target" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -n "$target" ] || continue
- targets="$targets $target"
+ if [ -n "$targets" ]; then
+ targets="$targets $target"
+ else
+ targets="$target"
+ fi
count=$((count + 1))
done < "$manifest"
@@ -45,11 +51,11 @@ if [ "$count" -eq 0 ]; then
exit 2
fi
-run_step test-rt-headers make -C "$repo_root" \
- RT_HEADER_TEST_TARGETS="$targets" test-rt-headers || exit $?
-
for target in $targets; do
out="$repo_root/build/test/rt-headers/$target/smoke.o"
+ mkdir -p "$(dirname "$out")"
+ run_step "rt-header-$target" "$KIT" cc -target "$target" -Werror \
+ -c "$repo_root/test/rt/smoke.c" -o "$out" || exit $?
if [ ! -s "$out" ]; then
printf 'tier1/runtime-headers: missing compiled header smoke: %s\n' "$out" >&2
exit 1
diff --git a/test/tier1/system/tools.sh b/test/tier1/system/tools.sh
@@ -9,18 +9,30 @@ manifest="$repo_root/test/tier1/manifests/system/tools.txt"
log_dir="${KIT_TIER1_LOG_DIR:-$repo_root/build/test/tier1/logs/system/tools}"
mkdir -p "$log_dir"
+. "$script_dir/../timing.sh"
run_step() {
name=$1
shift
log="$log_dir/$name.log"
+ start_ms=$(t1_now_ms)
printf 'tier1/tools: %s\n' "$name"
- if "$@" > "$log" 2>&1; then
- printf ' ok: %s\n' "$log"
+ "$@" > "$log" 2>&1
+ rc=$?
+ if [ "$rc" -eq 0 ]; then
+ if t1_slow_timing_enabled; then
+ printf ' ok: %s (%sms)\n' "$log" "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")"
+ else
+ printf ' ok: %s\n' "$log"
+ fi
return 0
fi
- rc=$?
- printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ if t1_slow_timing_enabled; then
+ printf ' FAIL: %s (exit %s, %sms)\n' "$log" "$rc" \
+ "$(t1_elapsed_ms "$start_ms" "$(t1_now_ms)")" >&2
+ else
+ printf ' FAIL: %s (exit %s)\n' "$log" "$rc" >&2
+ fi
tail -n 80 "$log" >&2
return "$rc"
}
@@ -31,15 +43,48 @@ if [ ! -f "$manifest" ]; then
fi
count=0
+order="$log_dir/.order.$$"
+: > "$order"
+jobs=$(t1_parallel_jobs) || exit $?
+
+start_step() {
+ target=$1
+ id=$(t1_step_id "$target")
+ out="$log_dir/.step-$id.out"
+ status="$log_dir/.step-$id.status"
+ printf '%s\t%s\t%s\n' "$id" "$out" "$status" >> "$order"
+ t1_parallel_wait_for_slot "$jobs"
+ (
+ if run_step "$target" make -C "$repo_root" "$target" > "$out" 2>&1; then
+ printf '0\n' > "$status"
+ else
+ printf '%s\n' "$?" > "$status"
+ fi
+ ) &
+}
+
while IFS= read -r target || [ -n "$target" ]; do
target=${target%%#*}
target=$(printf '%s' "$target" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[ -n "$target" ] || continue
count=$((count + 1))
- run_step "$target" make -C "$repo_root" "$target" || exit $?
+ start_step "$target"
done < "$manifest"
+wait || true
+
if [ "$count" -eq 0 ]; then
printf 'tier1/tools: manifest has no runnable targets: %s\n' "$manifest" >&2
exit 2
fi
+
+rc=0
+while IFS="$(printf '\t')" read -r id out status; do
+ [ -n "$id" ] || continue
+ cat "$out"
+ step_rc=$(cat "$status" 2>/dev/null || printf '1\n')
+ if [ "$step_rc" -ne 0 ] && [ "$rc" -eq 0 ]; then
+ rc=$step_rc
+ fi
+done < "$order"
+exit "$rc"
diff --git a/test/tier1/timing.sh b/test/tier1/timing.sh
@@ -0,0 +1,57 @@
+# Shared wall-clock helpers for Tier 1 shell wrappers.
+
+t1_now_ms() {
+ perl -MTime::HiRes=time -e 'printf "%.0f\n", time() * 1000' 2>/dev/null ||
+ printf '%s000\n' "$(date +%s 2>/dev/null || printf '0')"
+}
+
+t1_elapsed_ms() {
+ t1_em_start=$1
+ t1_em_end=$2
+ t1_em_dur=$((t1_em_end - t1_em_start))
+ [ "$t1_em_dur" -lt 0 ] && t1_em_dur=0
+ printf '%s\n' "$t1_em_dur"
+}
+
+t1_slow_timing_enabled() {
+ case "${KIT_TIER1_SLOW_TIMING:-0}" in
+ 1|yes|true|on) return 0 ;;
+ *) return 1 ;;
+ esac
+}
+
+t1_parallel_jobs() {
+ t1_pj_requested="${KIT_TIER1_JOBS:-${KIT_TEST_JOBS:-auto}}"
+ case "$t1_pj_requested" in
+ ""|1) printf '1\n'; return ;;
+ auto)
+ t1_pj_n=$(getconf _NPROCESSORS_ONLN 2>/dev/null || true)
+ [ -n "$t1_pj_n" ] || t1_pj_n=$(sysctl -n hw.ncpu 2>/dev/null || true)
+ case "$t1_pj_n" in ''|*[!0-9]*) t1_pj_n=1 ;; esac
+ [ "$t1_pj_n" -gt 6 ] && t1_pj_n=6
+ [ "$t1_pj_n" -lt 1 ] && t1_pj_n=1
+ printf '%s\n' "$t1_pj_n"
+ return ;;
+ *[!0-9]*)
+ printf 'invalid KIT_TIER1_JOBS=%s\n' "$t1_pj_requested" >&2
+ return 2 ;;
+ *)
+ [ "$t1_pj_requested" -lt 1 ] && t1_pj_requested=1
+ printf '%s\n' "$t1_pj_requested" ;;
+ esac
+}
+
+t1_parallel_running_count() {
+ jobs -pr | wc -l | tr -d '[:space:]'
+}
+
+t1_parallel_wait_for_slot() {
+ t1_pws_max=$1
+ while [ "$(t1_parallel_running_count)" -ge "$t1_pws_max" ]; do
+ sleep 0.05
+ done
+}
+
+t1_step_id() {
+ printf '%s' "$1" | tr -c 'A-Za-z0-9_.-' '_'
+}