mirror of
https://github.com/ruvnet/RuView.git
synced 2026-10-18 21:00:22 -05:00
* feat(forecast): add independent Rust training stack Signed-off-by: Codex <codex@openai.com> * docs(forecast): record informal HPO exploration note (unaccepted) Records an exploratory Darwin Mode numeric-genome hyperparameter search against the tiny_ci synthetic accuracy protocol: WQL improved 0.257 -> 0.161 -> 0.153 over two search rounds, staying ahead of both baselines throughout. Explicitly scoped as informal/exploratory (not a frozen leakage-free report, not eligible for the evidence ledger, not validated for large_linux or any real dataset) per this doc's own evidence-tagging discipline. * feat(forecast-core): add per-horizon weighted quantile loss weighted_quantile_loss collapses the whole horizon into one aggregate number, hiding whether error grows with lead time. Add a sibling function using the identical per-cell pinball formula and domain checks, just reduced per horizon step instead of globally. A unit test reconstructs the aggregate from the per-step numerators/ denominators to prove the two functions agree exactly, not just approximately. * feat(forecast-model): add evaluation-only local activation Adds activate_for_evaluation and build_eval_input, gated behind the cpu feature. activate_for_evaluation self-signs an unsigned candidate with a fixed, publicly-known, non-secret Ed25519 key so a CLI operator can run inference against their own just-trained candidate without a real release signature -- explicitly never a production trust path, documented as such in the module doc comment. The schema-digest check in ArtifactActivationPolicy still applies in full; only signing is relaxed. build_eval_input constructs a single-window ModelInput for CPU inference from raw context-major values/mask arrays, matching the training batch builders exact time-feature/descriptor encoding. Six unit tests cover: malformed-candidate rejection, digest-mismatch rejection (proving the schema check has teeth even on this relaxed path), getting past the policy gate with a matching digest, and eval-input shape validation. * feat(forecast-train): add evaluate and prepare-synthetic-dataset CLI Turns this sessions throwaway HPO scripts into real, tested CLI surfaces, replacing two example binaries that bypassed the CLI/TOML training path entirely. prepare-synthetic-dataset generates a larger, configurable synthetic training shard (default 24 windows) plus a matching train-local.toml with the given OptimizerSpec hyperparameters baked in, and a separate held-out test.jsonl -- the same synthetic-only, local-validation-only posture as prepare-local-example, just bigger and configurable. evaluate scores a trained (unsigned) candidate against held-out windows and the LastValue/SeasonalNaive baselines: overall weighted quantile loss, a per-horizon breakdown, 80% interval coverage, and missingness, for the model and both baselines. Explicitly lists what docs/benchmarks/ruforecast.mds full accuracy protocol additionally asks for that this does not cover (abstention coverage, selective risk, site/device slices, interference regime, RuVector-retrieval ablation) rather than silently omitting them -- each needs infrastructure a single-entity synthetic fixture does not have. Together the three real commands (prepare-synthetic-dataset, train-local, evaluate) reproduce the exact WQL numbers the old library-bypassing example scripts produced for the same hyperparameters, confirmed by re-running the harness/ruview HPO dry-run end to end against the new CLI path. New integration test trains a real candidate via smoke, evaluates it against held-out synthetic windows, and asserts the full report shape and an empty-input rejection. * feat(forecast-train): add prepare-synthetic-dataset --seed + Autogenous bridge --seed (default 0, backward compatible) makes prepare-synthetic-dataset's generator deterministic per offset: same seed -> byte-identical corpus across runs (needed to train two genomes on the SAME corpus for a fair comparison); different seeds -> genuinely independent corpora (needed for honest multi-seed/multi-judge evaluation upstream, both in harness/ruview/flywheel/ruforecast/gate.mjs's fitness function and in the new v2/crates/ruforecast-autogenous-bridge crate added here). ruforecast-autogenous-bridge is a LOCAL-DEV-ONLY (excluded from the v2 workspace, publish = false) bridge from this crate's real evaluate CLI into ruvnet/autogenous's new regression-candidate promotion path (separate, unpushed branch feat/regression-candidate-kind): runs N independent train+evaluate judges on genuinely distinct synthetic corpora, signs receipts, and gets a real cryptographically-verified PROMOTE/REJECT decision -- defense in depth on top of, not a replacement for, Darwin's own promotion gate. Path-depends on a sibling autogenous checkout that does not exist in CI; build/run directly via `cargo build --manifest-path crates/ruforecast-autogenous-bridge/Cargo.toml`. cargo test -p ruview-forecast-train --no-default-features --features cpu,cli: all green (unaffected existing tests + this backward-compatible addition). * docs(forecast): retract round-2 HPO result, record honest multi-seed finding The earlier "Informal HPO exploration note" claimed a real improvement (WQL 0.257 -> 0.153) from a 3-round hyperparameter search. That search evaluated every candidate against one fixed synthetic corpus (seed 0) for every round -- textbook overfitting. Independent verification against two fresh corpora (via the new ruforecast-autogenous-bridge crate) showed the "winner" losing to the baseline on both. Fixed the root cause in harness/ruview/flywheel/ruforecast/gate.mjs: candidates are now scored against three independent corpora, worst-case across them, not one fixed corpus. Re-ran the search under the fix. It found a new winner that genuinely beat baseline on all three of its own search seeds -- and that winner ALSO lost independent verification on fresh seeds. Two independent search rounds, pre- and post-fix, both produced an illusory "winner." The honest reading: at this dataset scale (24 synthetic windows) held-out WQL varies enormously by which corpus is drawn, regardless of hyperparameters -- confirmed directly by the baseline genome's own primary swinging from 0.83 to a full regression across the three fixed search seeds with unchanged hyperparameters. No RuForecast hyperparameter configuration has been shown to reliably beat the trivial baselines out-of-sample at this scale. Also fixes a real design inconsistency surfaced by this exploration: the Autogenous regression-candidate promotion verifier (envelope::regression::verify_regression_promotion, separate unpushed ruvnet/autogenous branch feat/regression-candidate-kind) required all judges to share one corpus_id, which conflicts with this kind's intentional cross-corpus judge design. Corrected there (commit bfa4c48); did not change either REJECT verdict, which were already driven by the real NotBetterThanParent signal on their own. Append-only: the original round-2 row is kept, read together with this new amendment section, per this doc's own evidence-ledger discipline. * refactor(forecast): extract RuForecast to ruvnet/RuForecast submodule Mirrors the v2/crates/worldgraph pattern: RuForecast becomes its own independent public repo/workspace (ruforecast-core/model/train), mounted at v2/crates/ruforecast as a git submodule, with v2/Cargo.toml path-depping into its sub-crates and excluding the submodule from the v2 workspace. Full v2 --workspace check passes; the ruforecast CLI builds and runs correctly from its new location. Real git history for the extracted crates (7 commits) was preserved via git-filter-repo, not squashed. * feat(autogenous-bridge): real-data independent verification tool real_data_verify.rs: signs two real, temporally-independent judge measurements (different train/test split boundaries on the same real household vitals corpus, not synthetic seeds) through the real Autogenous regression-candidate promotion path, and gets a genuine cryptographically-checked PROMOTE/REJECT verdict. Result recorded (see docs/benchmarks/ruforecast.md): REJECT. One judge nominally beat the trivial baseline but by less than the 0.01 non-inferiority margin; the other judge lost outright. Consistent with every synthetic-data search this session -- no configuration has yet been shown to reliably beat trivial baselines out-of-sample, now including a real 6390-sample household corpus. Bumps the ruforecast submodule to pick up the evaluate real-gap fix. * docs(forecast): record real-household-data result (REJECT, signed) 6390 real vital-signs samples, two independent temporal splits, independently verified via the real Autogenous regression-candidate promotion path. Signed verdict: REJECT -- neither split cleared the non-inferiority margin. Same conclusion as every synthetic search this session, now confirmed with real data too: more real data is the credible next lever, not further search on this scale of fixture. * chore(forecast): point ruforecast submodule at published main (post gap-tolerance fix) * ci(forecast): fix ruforecast-ci.yml for the new v2/crates/ruforecast submodule layout The RuForecast crates were extracted into a standalone submodule (v2/crates/ruforecast, mirroring the existing v2/crates/worldgraph pattern) and are no longer members of the v2 workspace. The CI workflow still referenced the old in-tree package names/paths (ruview-forecast-core/model/train under v2/), which broke every forecast job with "cannot specify features for packages outside of workspace". Fixed every job to target the submodule: working-directory -> v2/crates/ruforecast, -p ruview-forecast-* -> -p ruforecast-*, all hardcoded Cargo.toml/source paths in the Python assertion and clean-room-scan blocks, the Swatinem/rust-cache workspaces input, the artifact-tree output paths, and the two levels of relative path (../ -> ../../) in the informational-benchmark steps whose working directory moved one level deeper. Also collapsed the paths: trigger filters internal-crate globs (v2/crates/ruview-forecast-*/**) down to the single v2/crates/ruforecast path, since GitHub Actions path filters only ever see a submodule gitlink change as one entry in the parent tree, never its internal file paths -- the old globs could never have matched anything. Includes a real cargo fmt fix (submodule commit d9902f9) for formatting drift left over from the earlier real-data gap-tolerance fix, which the contract job's fmt --check step would otherwise have failed on. All four forecast CI jobs' real commands verified locally before push: cargo test/check for CPU, CUDA/WGPU compile-check, the contract job's Python assertion block, the hosted-boundaries clean-room scan, and cargo fmt --check. * docs(forecast): record real BIDMC cross-entity holdout result (REJECT) Two independent real-patient partitions (34/16 and 24/26 splits, 53 total ICU patients from PhysioNet BIDMC, Open Data Commons Attribution License v1.0) both show the model losing to trivial baselines by a decisive margin (+69% and +601% worse WQL). First genuine cross-entity real-data test this project has run; same conclusion as every prior synthetic and single-household test. Full Autogenous signed verification was not run for this entry - flagged explicitly in the note. * chore(forecast): point ruforecast submodule at published main (example feature-gate fix) * chore(forecast): point ruforecast submodule at published main (clippy fix) --------- Signed-off-by: Codex <codex@openai.com>
289 lines
10 KiB
Bash
Executable File
289 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Reproducible CPU benchmark evidence runner for ADR-348.
|
|
#
|
|
# This script never downloads a model or dataset and never enables CUDA. The
|
|
# benchmark fixtures are generated by the checked-in Rust benches, so the
|
|
# source commit and Cargo.lock digest identify the fixture implementation.
|
|
|
|
set -Eeuo pipefail
|
|
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd -P)"
|
|
|
|
TOOLCHAIN="${RUFORECAST_TOOLCHAIN:-1.92.0}"
|
|
THREADS="${RUFORECAST_THREADS:-1}"
|
|
WARM_UP_SECONDS="${RUFORECAST_WARM_UP_SECONDS:-3}"
|
|
MEASUREMENT_SECONDS="${RUFORECAST_MEASUREMENT_SECONDS:-10}"
|
|
SAMPLE_SIZE="${RUFORECAST_SAMPLE_SIZE:-30}"
|
|
CPUSET="${RUFORECAST_CPUSET:-}"
|
|
ALLOW_DIRTY="${RUFORECAST_ALLOW_DIRTY:-0}"
|
|
INCLUDE_LARGE="${RUFORECAST_BENCH_LARGE:-0}"
|
|
|
|
die() {
|
|
printf 'ruforecast benchmark: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_command() {
|
|
command -v "$1" >/dev/null 2>&1 || die "required command not found: $1"
|
|
}
|
|
|
|
require_uint() {
|
|
local name="$1"
|
|
local value="$2"
|
|
[[ "$value" =~ ^[0-9]+$ ]] || die "${name} must be an unsigned integer"
|
|
}
|
|
|
|
[[ "$TOOLCHAIN" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] \
|
|
|| die "RUFORECAST_TOOLCHAIN must be an exact Rust release such as 1.92.0"
|
|
require_uint RUFORECAST_THREADS "$THREADS"
|
|
require_uint RUFORECAST_WARM_UP_SECONDS "$WARM_UP_SECONDS"
|
|
require_uint RUFORECAST_MEASUREMENT_SECONDS "$MEASUREMENT_SECONDS"
|
|
require_uint RUFORECAST_SAMPLE_SIZE "$SAMPLE_SIZE"
|
|
(( THREADS >= 1 )) || die "RUFORECAST_THREADS must be at least 1"
|
|
(( WARM_UP_SECONDS >= 1 )) || die "RUFORECAST_WARM_UP_SECONDS must be at least 1"
|
|
(( MEASUREMENT_SECONDS >= 1 )) || die "RUFORECAST_MEASUREMENT_SECONDS must be at least 1"
|
|
(( SAMPLE_SIZE >= 10 )) || die "RUFORECAST_SAMPLE_SIZE must be at least 10 for Criterion"
|
|
[[ "$ALLOW_DIRTY" == "0" || "$ALLOW_DIRTY" == "1" ]] \
|
|
|| die "RUFORECAST_ALLOW_DIRTY must be 0 or 1"
|
|
[[ "$INCLUDE_LARGE" == "0" || "$INCLUDE_LARGE" == "1" ]] \
|
|
|| die "RUFORECAST_BENCH_LARGE must be 0 or 1"
|
|
|
|
if [[ -n "$CPUSET" ]]; then
|
|
[[ "$CPUSET" =~ ^[0-9,-]+$ ]] || die "RUFORECAST_CPUSET contains unsupported characters"
|
|
require_command taskset
|
|
fi
|
|
|
|
for command_name in cargo rustc git jq sha256sum; do
|
|
require_command "$command_name"
|
|
done
|
|
|
|
cd "$REPO_ROOT"
|
|
|
|
for manifest in \
|
|
v2/crates/ruview-forecast-core/Cargo.toml \
|
|
v2/crates/ruview-forecast-model/Cargo.toml \
|
|
v2/crates/ruview-forecast-train/Cargo.toml; do
|
|
[[ -f "$manifest" ]] || die "forecast crate is missing: $manifest"
|
|
done
|
|
|
|
WORKTREE_CLEAN=true
|
|
if [[ -n "$(git status --porcelain)" ]]; then
|
|
WORKTREE_CLEAN=false
|
|
[[ "$ALLOW_DIRTY" == "1" ]] \
|
|
|| die "worktree changes detected; commit them or set RUFORECAST_ALLOW_DIRTY=1 for diagnostic evidence"
|
|
fi
|
|
|
|
COMMIT="$(git rev-parse HEAD)"
|
|
SHORT_COMMIT="$(git rev-parse --short=12 HEAD)"
|
|
LOCK_SHA256="$(sha256sum v2/Cargo.lock | awk '{print $1}')"
|
|
RUN_UTC="$(date -u +'%Y%m%dT%H%M%SZ')"
|
|
SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)"
|
|
|
|
DEFAULT_OUTPUT="${REPO_ROOT}/target/ruforecast-evidence/${RUN_UTC}-${SHORT_COMMIT}"
|
|
OUTPUT_DIR="${RUFORECAST_OUTPUT_DIR:-$DEFAULT_OUTPUT}"
|
|
if [[ "$OUTPUT_DIR" != /* ]]; then
|
|
OUTPUT_DIR="${REPO_ROOT}/${OUTPUT_DIR}"
|
|
fi
|
|
if [[ -d "$OUTPUT_DIR" && -n "$(find "$OUTPUT_DIR" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then
|
|
die "output directory is not empty: $OUTPUT_DIR"
|
|
fi
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
finalize_evidence() {
|
|
local exit_status=$?
|
|
local sums_status=0
|
|
local sums_tmp=""
|
|
trap - EXIT
|
|
set +e
|
|
|
|
if [[ -d "${OUTPUT_DIR:-}" ]]; then
|
|
if (( exit_status == 0 )); then
|
|
printf 'status=PASSED\nexit_code=0\n' >"${OUTPUT_DIR}/run-status.txt"
|
|
else
|
|
printf 'status=FAILED\nexit_code=%d\n' "$exit_status" \
|
|
>"${OUTPUT_DIR}/run-status.txt"
|
|
fi
|
|
|
|
sums_tmp="$(mktemp "${OUTPUT_DIR}.SHA256SUMS.XXXXXX")" || sums_status=$?
|
|
if (( sums_status == 0 )); then
|
|
(
|
|
cd "$OUTPUT_DIR" || exit
|
|
find . -maxdepth 1 -type f ! -name SHA256SUMS -printf '%P\0' \
|
|
| sort -z \
|
|
| xargs -0 sha256sum
|
|
) >"$sums_tmp" || sums_status=$?
|
|
fi
|
|
if (( sums_status == 0 )); then
|
|
mv "$sums_tmp" "${OUTPUT_DIR}/SHA256SUMS" || sums_status=$?
|
|
elif [[ -n "$sums_tmp" ]]; then
|
|
rm -f "$sums_tmp"
|
|
fi
|
|
fi
|
|
|
|
if (( exit_status == 0 && sums_status != 0 )); then
|
|
exit_status=$sums_status
|
|
fi
|
|
exit "$exit_status"
|
|
}
|
|
trap finalize_evidence EXIT
|
|
|
|
export RAYON_NUM_THREADS="$THREADS"
|
|
export OMP_NUM_THREADS="$THREADS"
|
|
export OPENBLAS_NUM_THREADS="$THREADS"
|
|
export MKL_NUM_THREADS="$THREADS"
|
|
export NUMEXPR_NUM_THREADS="$THREADS"
|
|
export CARGO_PROFILE_BENCH_DEBUG=0
|
|
export CARGO_PROFILE_RELEASE_DEBUG=0
|
|
export CARGO_INCREMENTAL=0
|
|
export RUST_BACKTRACE=1
|
|
export SOURCE_DATE_EPOCH
|
|
export TZ=UTC
|
|
export LC_ALL=C
|
|
export RUFORECAST_BENCH_LARGE="$INCLUDE_LARGE"
|
|
|
|
CARGO=(cargo "+${TOOLCHAIN}")
|
|
if [[ -n "$CPUSET" ]]; then
|
|
CARGO=(taskset -c "$CPUSET" cargo "+${TOOLCHAIN}")
|
|
fi
|
|
|
|
"${CARGO[@]}" --version >"${OUTPUT_DIR}/cargo-version.txt"
|
|
if [[ -n "$CPUSET" ]]; then
|
|
taskset -c "$CPUSET" rustc "+${TOOLCHAIN}" -vV >"${OUTPUT_DIR}/rustc-version.txt"
|
|
else
|
|
rustc "+${TOOLCHAIN}" -vV >"${OUTPUT_DIR}/rustc-version.txt"
|
|
fi
|
|
if command -v lscpu >/dev/null 2>&1; then
|
|
lscpu -J >"${OUTPUT_DIR}/cpu.json"
|
|
fi
|
|
uname -srmo >"${OUTPUT_DIR}/kernel.txt"
|
|
if [[ -r /etc/os-release ]]; then
|
|
cp /etc/os-release "${OUTPUT_DIR}/os-release.txt"
|
|
fi
|
|
if command -v free >/dev/null 2>&1; then
|
|
free -b >"${OUTPUT_DIR}/memory.txt"
|
|
fi
|
|
|
|
printf \
|
|
'RUFORECAST_TOOLCHAIN=%q RUFORECAST_THREADS=%q RUFORECAST_CPUSET=%q RUFORECAST_WARM_UP_SECONDS=%q RUFORECAST_MEASUREMENT_SECONDS=%q RUFORECAST_SAMPLE_SIZE=%q RUFORECAST_ALLOW_DIRTY=%q RUFORECAST_BENCH_LARGE=%q scripts/run-ruforecast-benchmarks.sh\n' \
|
|
"$TOOLCHAIN" \
|
|
"$THREADS" \
|
|
"$CPUSET" \
|
|
"$WARM_UP_SECONDS" \
|
|
"$MEASUREMENT_SECONDS" \
|
|
"$SAMPLE_SIZE" \
|
|
"$ALLOW_DIRTY" \
|
|
"$INCLUDE_LARGE" \
|
|
>"${OUTPUT_DIR}/reproducer.txt"
|
|
|
|
EVIDENCE_LABEL="MEASURED"
|
|
EVIDENCE_SCOPE="LOCAL_CPU_SYNTHETIC_FIXTURE"
|
|
if [[ "$WORKTREE_CLEAN" != "true" ]]; then
|
|
EVIDENCE_LABEL="SYNTHETIC"
|
|
EVIDENCE_SCOPE="DIRTY_WORKTREE_DIAGNOSTIC_ONLY"
|
|
fi
|
|
|
|
jq -n \
|
|
--arg schema_version "1" \
|
|
--arg evidence_label "$EVIDENCE_LABEL" \
|
|
--arg evidence_scope "$EVIDENCE_SCOPE" \
|
|
--arg commit "$COMMIT" \
|
|
--arg lock_sha256 "$LOCK_SHA256" \
|
|
--arg toolchain "$TOOLCHAIN" \
|
|
--arg run_utc "$RUN_UTC" \
|
|
--argjson source_date_epoch "$SOURCE_DATE_EPOCH" \
|
|
--arg cpuset "$CPUSET" \
|
|
--argjson include_large "$INCLUDE_LARGE" \
|
|
--argjson worktree_clean "$WORKTREE_CLEAN" \
|
|
--argjson threads "$THREADS" \
|
|
--argjson warm_up_seconds "$WARM_UP_SECONDS" \
|
|
--argjson measurement_seconds "$MEASUREMENT_SECONDS" \
|
|
--argjson sample_size "$SAMPLE_SIZE" \
|
|
'{
|
|
schema_version: ($schema_version | tonumber),
|
|
evidence_label: $evidence_label,
|
|
evidence_scope: $evidence_scope,
|
|
claim_status: "UNREVIEWED",
|
|
input_class: "SYNTHETIC",
|
|
backend: "burn-ndarray-cpu",
|
|
cuda_enabled: false,
|
|
source: {
|
|
commit: $commit,
|
|
cargo_lock_sha256: $lock_sha256,
|
|
worktree_clean: $worktree_clean,
|
|
source_date_epoch: $source_date_epoch
|
|
},
|
|
environment: {
|
|
rust_toolchain: $toolchain,
|
|
threads: $threads,
|
|
cpuset: (if $cpuset == "" then null else $cpuset end)
|
|
},
|
|
criterion: {
|
|
warm_up_seconds: $warm_up_seconds,
|
|
measurement_seconds: $measurement_seconds,
|
|
sample_size: $sample_size,
|
|
include_large_profile: ($include_large == 1)
|
|
},
|
|
run_utc: $run_utc,
|
|
caveat: "Criterion timing is host-specific. This report is not a RuView capability claim until reviewed against ADR-348."
|
|
}' >"${OUTPUT_DIR}/metadata.json"
|
|
|
|
run_logged() {
|
|
local log_name="$1"
|
|
shift
|
|
"$@" 2>&1 | tee "${OUTPUT_DIR}/${log_name}.log"
|
|
}
|
|
|
|
run_logged core-tests \
|
|
"${CARGO[@]}" test --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-core --no-default-features --lib --tests
|
|
|
|
run_logged model-cpu-tests \
|
|
"${CARGO[@]}" test --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-model --no-default-features --features cpu --lib --tests
|
|
|
|
run_logged train-cpu-tests \
|
|
"${CARGO[@]}" test --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-train --no-default-features --features cpu,cli --lib --bins
|
|
|
|
run_logged local-jsonl-training-smoke \
|
|
"${CARGO[@]}" test --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-train --no-default-features --features cpu \
|
|
--test local_jsonl_smoke -- \
|
|
--exact local_hash_addressed_jsonl_executes_one_real_optimizer_step
|
|
|
|
run_logged cli-smoke-idempotency \
|
|
"${CARGO[@]}" test --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-train --no-default-features --features cpu,cli \
|
|
--test cli_smoke -- \
|
|
--exact cli_smoke_trains_and_writes_the_complete_candidate_set
|
|
|
|
run_logged forecast-inference-compile \
|
|
"${CARGO[@]}" bench --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-model --no-default-features --features cpu \
|
|
--bench forecast_inference --no-run
|
|
|
|
run_logged data-pipeline-compile \
|
|
"${CARGO[@]}" bench --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-train --no-default-features --features cpu \
|
|
--bench data_pipeline --no-run
|
|
|
|
run_logged forecast-inference \
|
|
"${CARGO[@]}" bench --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-model --no-default-features --features cpu \
|
|
--bench forecast_inference -- \
|
|
--warm-up-time "$WARM_UP_SECONDS" \
|
|
--measurement-time "$MEASUREMENT_SECONDS" \
|
|
--sample-size "$SAMPLE_SIZE"
|
|
|
|
run_logged data-pipeline \
|
|
"${CARGO[@]}" bench --manifest-path v2/Cargo.toml --locked \
|
|
-p ruview-forecast-train --no-default-features --features cpu \
|
|
--bench data_pipeline -- \
|
|
--warm-up-time "$WARM_UP_SECONDS" \
|
|
--measurement-time "$MEASUREMENT_SECONDS" \
|
|
--sample-size "$SAMPLE_SIZE"
|
|
|
|
printf 'RuForecast CPU outputs collected; finalizing hashes in %s\n' "$OUTPUT_DIR"
|
|
printf 'Review metadata.json and the two Criterion logs before accepting or publishing evidence.\n'
|