test: split fast/full, parallelize 995, race-correct two-phase test/run
test/run fans out test/wcc/*.c except 950 and 990-997 across $(nproc) xargs workers, then runs the byte-id gates sequentially in phase 2. Each worker writes <prefix>.status into a mktemp results dir; the collector emits them in glob order for deterministic output. Phase 2 sequentiality sidesteps the race introduced by ww_ww writing intermediates next to every traversed source (#15) — concurrent reads of selfhost/cmd/<tool>/main.{combined.ww,s,o} would see partial bytes (#16). `make test-unit` (UNIT=1) skips phase 2 entirely for a 3.8s inner-loop check; `make test` runs the full 132 in ~8:30. test-unit goal aligns with the selfhost-bootstrap project goal: 990-997 + 950 are the toolchain-rebuild gates, fast feedback is for unit work below them. 990-995 wrap every ww/w6c/w6a/w6l/wwdump invocation in `timeout 180`; 995's hardcoded /tmp/ww_d_hello.ww is now pid-keyed. 995 forks its 5 ww_ww builds concurrently (waitpid for collection) so its solo wall drops from 3:15 to 1:32. Phase-2 split (parallel readers + sequential writers) deferred to #17, post #15. Wall: 9:59 → 8:32 (full) / 3.8s (test-unit, ~158× from baseline).
This commit is contained in:
5
Makefile
5
Makefile
@@ -935,6 +935,9 @@ sizelint:
|
|||||||
test: all sizelint $(TESTS)
|
test: all sizelint $(TESTS)
|
||||||
@WW=$(BIN)/ww BIN=$(BIN) sh test/run
|
@WW=$(BIN)/ww BIN=$(BIN) sh test/run
|
||||||
|
|
||||||
|
test-unit: all sizelint $(TESTS)
|
||||||
|
@WW=$(BIN)/ww BIN=$(BIN) UNIT=1 sh test/run
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
mkdir -p $(PREFIX)/bin $(PREFIX)/lib
|
mkdir -p $(PREFIX)/bin $(PREFIX)/lib
|
||||||
cp $(BIN)/ww $(PREFIX)/bin/
|
cp $(BIN)/ww $(PREFIX)/bin/
|
||||||
@@ -1080,4 +1083,4 @@ nocc:
|
|||||||
@echo
|
@echo
|
||||||
@echo "NOCC OK: $(STAGE0)/* reproduces itself from source. cc not invoked."
|
@echo "NOCC OK: $(STAGE0)/* reproduces itself from source. cc not invoked."
|
||||||
|
|
||||||
.PHONY: all cstage wwstage test sizelint install clean bootstrap nocc bootstrap-snapshot
|
.PHONY: all cstage wwstage test test-unit sizelint install clean bootstrap nocc bootstrap-snapshot
|
||||||
|
|||||||
25
test/run
25
test/run
@@ -46,15 +46,34 @@ trap 'rm -rf "$RESULTS"' EXIT
|
|||||||
|
|
||||||
JOBS=${JOBS:-$(nproc 2>/dev/null || echo 4)}
|
JOBS=${JOBS:-$(nproc 2>/dev/null || echo 4)}
|
||||||
|
|
||||||
# Emit (prefix, testpath) pairs NUL-separated. The prefix carries the
|
# Phase 2 runs the wwstage byte-id gates (990-997) + 950_selfcheck
|
||||||
# test's <NNN>_<name> stem so the collector iterates in lexical order,
|
# sequentially. ww_ww writes intermediates next to every traversed source
|
||||||
# yielding deterministic output even though workers interleave.
|
# (task #15), so 991/992/994's reads of selfhost/cmd/<tool>/main.{s,o,
|
||||||
|
# combined.ww} race against any concurrent driver-using test that emits
|
||||||
|
# a sibling .combined.ww (task #16). Phase 1 stays parallel for unit
|
||||||
|
# coverage; phase 2 sequential keeps the byte-id gates honest.
|
||||||
for t in test/wcc/*.c; do
|
for t in test/wcc/*.c; do
|
||||||
[ -f "$t" ] || continue
|
[ -f "$t" ] || continue
|
||||||
|
case ${t##*/} in
|
||||||
|
950_*|990_*|991_*|992_*|993_*|994_*|995_*|996_*|997_*) continue ;;
|
||||||
|
esac
|
||||||
name=${t##*/}; name=${name%.c}
|
name=${t##*/}; name=${name%.c}
|
||||||
printf '%s/%s\0%s\0' "$RESULTS" "$name" "$t"
|
printf '%s/%s\0%s\0' "$RESULTS" "$name" "$t"
|
||||||
done | xargs -0 -n2 -P "$JOBS" "$0" --one || true
|
done | xargs -0 -n2 -P "$JOBS" "$0" --one || true
|
||||||
|
|
||||||
|
# UNIT=1 (make test-unit) is the inner-loop short path: skip the wwstage
|
||||||
|
# byte-id gates (990-997) and 950_selfcheck entirely. Pre-push uses
|
||||||
|
# `make test` for the full suite.
|
||||||
|
if [ "${UNIT:-0}" != "1" ]; then
|
||||||
|
for t in test/wcc/950_*.c test/wcc/990_*.c test/wcc/991_*.c \
|
||||||
|
test/wcc/992_*.c test/wcc/993_*.c test/wcc/994_*.c \
|
||||||
|
test/wcc/995_*.c test/wcc/996_*.c test/wcc/997_*.c; do
|
||||||
|
[ -f "$t" ] || continue
|
||||||
|
name=${t##*/}; name=${name%.c}
|
||||||
|
"$0" --one "$RESULTS/$name" "$t" || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
fail=0
|
fail=0
|
||||||
ran=0
|
ran=0
|
||||||
for s in "$RESULTS"/*.status; do
|
for s in "$RESULTS"/*.status; do
|
||||||
|
|||||||
@@ -82,21 +82,18 @@ struct buildjob {
|
|||||||
/* Fork a child that runs the `ww_ww build` for this tool. The child
|
/* Fork a child that runs the `ww_ww build` for this tool. The child
|
||||||
* inherits no concurrent siblings — system() spawns a fresh /bin/sh -c.
|
* inherits no concurrent siblings — system() spawns a fresh /bin/sh -c.
|
||||||
* stderr lands in <workdir>/build.err so concurrent builds don't merge
|
* stderr lands in <workdir>/build.err so concurrent builds don't merge
|
||||||
* their diagnostics.
|
* their diagnostics. The driver leaves intermediates next to every
|
||||||
*
|
* source it traverses (selfhost/cmd/<tool>/main.s, etc.) — task #15 in
|
||||||
* The source is staged at <workdir>/build.ww before the build so the
|
* the queue will let us redirect via `-o <outdir>`; until then, test/run
|
||||||
* driver writes its .combined.ww/.s/.o intermediates inside workdir —
|
* serializes 990/995 after the parallel phase. */
|
||||||
* not next to the canonical selfhost/cmd/<tool>/main.ww, where 991/992/
|
|
||||||
* 994 read main.s as a fixture. Without staging, parallel test/run sees
|
|
||||||
* 991 race against 995's wwdump-build mid-write of main.s. */
|
|
||||||
static int
|
static int
|
||||||
spawn_build(const char *bin, const char *cwd, struct buildjob *j)
|
spawn_build(const char *bin, const char *cwd, struct buildjob *j)
|
||||||
{
|
{
|
||||||
snprintf(j->workdir, sizeof j->workdir, "/tmp/wwsr_%d_%s",
|
snprintf(j->workdir, sizeof j->workdir, "/tmp/wwsr_%d_%s",
|
||||||
getpid(), j->tool);
|
getpid(), j->tool);
|
||||||
char setup[4096];
|
char setup[256];
|
||||||
snprintf(setup, sizeof setup, "rm -rf %s && mkdir -p %s && cp %s/%s %s/build.ww",
|
snprintf(setup, sizeof setup, "rm -rf %s && mkdir -p %s",
|
||||||
j->workdir, j->workdir, cwd, j->src_rel, j->workdir);
|
j->workdir, j->workdir);
|
||||||
if (runwait(setup) != 0) return -1;
|
if (runwait(setup) != 0) return -1;
|
||||||
|
|
||||||
char cmd[4096];
|
char cmd[4096];
|
||||||
@@ -104,15 +101,15 @@ spawn_build(const char *bin, const char *cwd, struct buildjob *j)
|
|||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"cd %s && timeout 180 %s/ww_ww build -I %s/%s "
|
"cd %s && timeout 180 %s/ww_ww build -I %s/%s "
|
||||||
"-I %s/lib/ww -I %s/lib/ww/lex -I %s/lib/ww/parse "
|
"-I %s/lib/ww -I %s/lib/ww/lex -I %s/lib/ww/parse "
|
||||||
"-I %s/selfhost/cmd/wcc build.ww >/dev/null 2>%s/build.err",
|
"-I %s/selfhost/cmd/wcc %s/%s >/dev/null 2>%s/build.err",
|
||||||
j->workdir, bin, cwd, j->inc_local,
|
j->workdir, bin, cwd, j->inc_local,
|
||||||
cwd, cwd, cwd, cwd, j->workdir);
|
cwd, cwd, cwd, cwd, cwd, j->src_rel, j->workdir);
|
||||||
} else {
|
} else {
|
||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"cd %s && timeout 180 %s/ww_ww build "
|
"cd %s && timeout 180 %s/ww_ww build "
|
||||||
"-I %s/lib/ww -I %s/lib/ww/lex -I %s/lib/ww/parse "
|
"-I %s/lib/ww -I %s/lib/ww/lex -I %s/lib/ww/parse "
|
||||||
"-I %s/selfhost/cmd/wcc build.ww >/dev/null 2>%s/build.err",
|
"-I %s/selfhost/cmd/wcc %s/%s >/dev/null 2>%s/build.err",
|
||||||
j->workdir, bin, cwd, cwd, cwd, cwd, j->workdir);
|
j->workdir, bin, cwd, cwd, cwd, cwd, cwd, j->src_rel, j->workdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t p = fork();
|
pid_t p = fork();
|
||||||
@@ -152,7 +149,7 @@ collect_build(const char *bin, struct buildjob *j)
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
} else {
|
} else {
|
||||||
char rebuilt[256], canonical[256];
|
char rebuilt[256], canonical[256];
|
||||||
snprintf(rebuilt, sizeof rebuilt, "%s/build", j->workdir);
|
snprintf(rebuilt, sizeof rebuilt, "%s/main", j->workdir);
|
||||||
snprintf(canonical, sizeof canonical, "%s/%s_ww", bin, j->tool);
|
snprintf(canonical, sizeof canonical, "%s/%s_ww", bin, j->tool);
|
||||||
rc = slurp_eq(rebuilt, canonical);
|
rc = slurp_eq(rebuilt, canonical);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user