Skip to content

Commit a4cfa79

Browse files
committed
fp-stability: install Verrou from prebuilt artifact (verrou-dist), build as fallback
verrou.sh now downloads a pinned, hash-verified prebuilt from sbryngelson/verrou-dist@v1 (seconds) and falls back to the ~20-min source build; idempotency check sources env.sh so a relocated prebuilt isn't re-fetched. fp_stability sets VALGRIND_LIB (via _verrou_env, reused by _dd_env) so a relocated tree's valgrind/verrou_dd_* calls resolve — harmless for source builds. CI installs zstd and sources env.sh before verifying.
1 parent c27b6ae commit a4cfa79

3 files changed

Lines changed: 95 additions & 14 deletions

File tree

.github/workflows/fp-stability.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,26 @@ jobs:
6868
uses: actions/cache@v4
6969
with:
7070
path: ~/.local/verrou
71-
# Keep these versions in sync with toolchain/bootstrap/verrou.sh (the builder).
71+
# Keep these versions in sync with toolchain/bootstrap/verrou.sh (the installer).
7272
key: verrou-a58d434-valgrind-3.26.0-${{ runner.os }}
7373

7474
- name: Install system dependencies
7575
run: |
7676
sudo apt-get update -y
7777
sudo apt-get install -y \
7878
build-essential automake python3 python3-numpy libc6-dbg \
79-
cmake gfortran
79+
cmake gfortran zstd
8080
81-
- name: Build Verrou
81+
- name: Install Verrou (prebuilt artifact, or source build as fallback)
8282
if: steps.cache-verrou.outputs.cache-hit != 'true'
8383
run: bash toolchain/bootstrap/verrou.sh
8484

8585
- name: Verify Verrou
86-
run: ~/.local/verrou/bin/valgrind --tool=verrou --version
86+
# Source env.sh first: a prebuilt (relocated) tree needs VALGRIND_LIB; a
87+
# source build works either way. (fp-stability sets this itself at runtime.)
88+
run: |
89+
[ -f ~/.local/verrou/env.sh ] && . ~/.local/verrou/env.sh
90+
~/.local/verrou/bin/valgrind --tool=verrou --version
8791
8892
- name: Build MFC (debug, serial)
8993
# FFLAGS=-fno-inline prevents gfortran from inlining small functions into

toolchain/bootstrap/verrou.sh

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,34 @@
22
#
33
# Opt-in installer for Verrou (the Valgrind FP-perturbation tool used by
44
# `./mfc.sh fp-stability`). Verrou is NOT a Python/pip package — it is a fork of
5-
# Valgrind that must be compiled from source (~20 min), so this is a deliberate,
6-
# explicit step rather than something `fp-stability` does silently.
5+
# Valgrind. By default this downloads a prebuilt, hash-verified artifact (seconds);
6+
# if none is available for this tag/arch it falls back to a source build (~20 min).
7+
# Either way it's a deliberate, explicit step, not something fp-stability does silently.
78
#
8-
# bash toolchain/bootstrap/verrou.sh # build into $HOME/.local/verrou
9+
# bash toolchain/bootstrap/verrou.sh # install into $HOME/.local/verrou
910
# VERROU_HOME=/path bash toolchain/bootstrap/verrou.sh
10-
# bash toolchain/bootstrap/verrou.sh --force # rebuild even if present
11+
# bash toolchain/bootstrap/verrou.sh --force # reinstall even if present
12+
# VERROU_BUILD_FROM_SOURCE=1 bash toolchain/bootstrap/verrou.sh # skip the prebuilt
1113
#
1214
# Versions are pinned to match the fp-stability CI workflow.
1315

1416
set -euo pipefail
1517

1618
VALGRIND_VERSION="3.26.0"
1719
VERROU_COMMIT="a58d434"
20+
# Prebuilt artifacts (built once per arch) live in a small companion repo. The tag
21+
# pins to the (valgrind, verrou) pair above — bump all three together.
22+
VERROU_DIST_REPO="${VERROU_DIST_REPO:-sbryngelson/verrou-dist}"
23+
VERROU_DIST_TAG="${VERROU_DIST_TAG:-v1}"
1824
PREFIX="${VERROU_HOME:-$HOME/.local/verrou}"
1925
FORCE="${1:-}"
2026

2127
echo "==> Verrou bootstrap (Valgrind ${VALGRIND_VERSION} + edf-hpc/verrou@${VERROU_COMMIT}) -> ${PREFIX}"
2228

23-
# Idempotent: skip if already installed and working.
24-
if [ "$FORCE" != "--force" ] && [ -x "${PREFIX}/bin/valgrind" ] && "${PREFIX}/bin/valgrind" --tool=verrou --version >/dev/null 2>&1; then
29+
# Idempotent: skip if already installed and working. Source env.sh first if present
30+
# (a prebuilt tree needs VALGRIND_LIB to run; a source build works either way).
31+
if [ "$FORCE" != "--force" ] && [ -x "${PREFIX}/bin/valgrind" ] \
32+
&& ( [ -f "${PREFIX}/env.sh" ] && . "${PREFIX}/env.sh"; "${PREFIX}/bin/valgrind" --tool=verrou --version >/dev/null 2>&1 ); then
2533
echo "==> Verrou already installed at ${PREFIX} (use --force to rebuild). Nothing to do."
2634
exit 0
2735
fi
@@ -31,9 +39,11 @@ if [ "$(uname -s)" != "Linux" ]; then
3139
echo "ERROR: Verrou requires Linux (Valgrind does not support modern macOS, incl. Apple Silicon)." >&2
3240
exit 1
3341
fi
42+
arch_tag=""
3443
case "$(uname -m)" in
35-
x86_64) ;;
44+
x86_64) arch_tag="x86_64" ;;
3645
aarch64|arm64)
46+
arch_tag="aarch64"
3747
echo "WARNING: $(uname -m) detected. Valgrind builds here, but Verrou's FP backends are" >&2
3848
echo " best-validated on x86_64 — treat results as experimental on this arch." >&2
3949
;;
@@ -42,6 +52,59 @@ case "$(uname -m)" in
4252
;;
4353
esac
4454

55+
# Fast path: download a prebuilt, hash-verified artifact and source its relocatable
56+
# env.sh, instead of building from source. Any failure (no asset for this arch/tag,
57+
# missing zstd/sha256sum, checksum mismatch, won't run) falls through to the build.
58+
try_prebuilt() {
59+
[ -n "$arch_tag" ] || return 1
60+
[ "${VERROU_BUILD_FROM_SOURCE:-}" = "1" ] && return 1
61+
command -v sha256sum >/dev/null 2>&1 || return 1
62+
tar --zstd --help >/dev/null 2>&1 || command -v zstd >/dev/null 2>&1 || return 1
63+
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 || return 1
64+
65+
local asset base dl
66+
asset="verrou-${VERROU_COMMIT}-valgrind-${VALGRIND_VERSION}-linux-${arch_tag}.tar.zst"
67+
base="https://github.com/${VERROU_DIST_REPO}/releases/download/${VERROU_DIST_TAG}/${asset}"
68+
dl="$(mktemp -d)"
69+
70+
echo "==> Trying prebuilt ${VERROU_DIST_REPO}@${VERROU_DIST_TAG} (${asset})"
71+
_fetch() { # url dest
72+
if command -v curl >/dev/null 2>&1; then curl -fsSL -o "$2" "$1"; else wget -q -O "$2" "$1"; fi
73+
}
74+
if ! _fetch "$base" "$dl/$asset" || ! _fetch "$base.sha256" "$dl/$asset.sha256"; then
75+
echo "==> No prebuilt for this tag/arch — building from source instead."
76+
rm -rf "$dl"; return 1
77+
fi
78+
if ! ( cd "$dl" && sha256sum -c "$asset.sha256" >/dev/null 2>&1 ); then
79+
echo "WARNING: prebuilt checksum mismatch — building from source instead." >&2
80+
rm -rf "$dl"; return 1
81+
fi
82+
83+
mkdir -p "$PREFIX"
84+
if tar --zstd --help >/dev/null 2>&1; then
85+
tar -C "$PREFIX" --zstd -xf "$dl/$asset"
86+
else
87+
zstd -dc "$dl/$asset" | tar -C "$PREFIX" -xf -
88+
fi
89+
rm -rf "$dl"
90+
91+
# Valgrind bakes its build prefix into the binary; the artifact's env.sh sets
92+
# VALGRIND_LIB relative to the extracted tree so the relocated install works.
93+
if ! ( . "${PREFIX}/env.sh" && "${PREFIX}/bin/valgrind" --tool=verrou --version >/dev/null 2>&1 ); then
94+
echo "WARNING: prebuilt did not run — building from source instead." >&2
95+
return 1
96+
fi
97+
return 0
98+
}
99+
100+
if try_prebuilt; then
101+
echo "==> Verifying"
102+
( . "${PREFIX}/env.sh" && "${PREFIX}/bin/valgrind" --tool=verrou --version )
103+
echo "==> Done (prebuilt). Verrou installed at ${PREFIX}"
104+
echo " Run: ./mfc.sh fp-stability (or set VERROU_HOME=${PREFIX} if you used a custom prefix)"
105+
exit 0
106+
fi
107+
45108
# Build dependencies.
46109
missing=""
47110
for tool in tar git make patch autoconf automake; do

toolchain/mfc/fp_stability_runners.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ def _verrou_pythonpath(verrou_bin: str) -> str:
6060
return matches[0] if matches else ""
6161

6262

63+
def _verrou_env(verrou_bin: str) -> dict:
64+
"""os.environ plus VALGRIND_LIB, so a relocated install tree (e.g. a prebuilt
65+
artifact extracted to a new prefix) can locate its tool — Valgrind bakes its
66+
build prefix into the binary otherwise. Harmless for a source-built tree, where
67+
VALGRIND_LIB just equals the compiled-in path. A VALGRIND_LIB already in the
68+
environment (user sourced env.sh) is left untouched."""
69+
env = os.environ.copy()
70+
libdir = os.path.join(os.path.dirname(os.path.dirname(verrou_bin)), "libexec", "valgrind")
71+
if "VALGRIND_LIB" not in env and os.path.isdir(libdir):
72+
env["VALGRIND_LIB"] = libdir
73+
return env
74+
75+
6376
def _write_inp(params: dict, target_name: str, work_dir: str) -> None:
6477
"""Write a Fortran namelist .inp file from a Python params dict."""
6578
from .run import case_dicts
@@ -107,7 +120,7 @@ def _run_simulation_verrou(
107120
cmd.append(sim_bin)
108121

109122
with open(os.path.join(run_dir, "sim.out"), "w") as f:
110-
result = subprocess.run(cmd, cwd=tmpdir, stdout=f, stderr=subprocess.STDOUT, check=False)
123+
result = subprocess.run(cmd, cwd=tmpdir, env=_verrou_env(verrou_bin), stdout=f, stderr=subprocess.STDOUT, check=False)
111124

112125
if result.returncode != 0:
113126
tag = rounding_mode or "vprec"
@@ -312,9 +325,10 @@ def _write_dd_cmp_py(path: str, compare_files: list, threshold: float):
312325

313326

314327
def _dd_env(verrou_bin: str) -> dict:
315-
"""Environment with PYTHONPATH set for verrou_dd_* imports."""
328+
"""Environment for verrou_dd_*: VALGRIND_LIB (so a relocated tree's inner valgrind
329+
calls resolve) plus PYTHONPATH (for the verrou_dd_* imports)."""
316330
py_pkg = _verrou_pythonpath(verrou_bin)
317-
env = os.environ.copy()
331+
env = _verrou_env(verrou_bin)
318332
if py_pkg:
319333
existing = env.get("PYTHONPATH", "")
320334
env["PYTHONPATH"] = ":".join(filter(None, [py_pkg, existing]))

0 commit comments

Comments
 (0)