Skip to content

Commit f1552c1

Browse files
authored
Merge pull request #6 from MFlowCode/master
Merge MFC changes into ibdata-output
2 parents dedf570 + 506c6f5 commit f1552c1

53 files changed

Lines changed: 2006 additions & 973 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/scripts/monitor_slurm_job.sh

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ cleanup() {
99
if [ -n "${tail_pid:-}" ]; then
1010
kill "${tail_pid}" 2>/dev/null || true
1111
fi
12-
# Cancel the SLURM job if the monitor is exiting due to an error
13-
# (e.g., the CI runner is being killed). Don't cancel on success.
12+
# Cancel the SLURM job only if it is still active in the scheduler.
13+
# If the job already left the queue (squeue returns empty), it has finished
14+
# and run_monitored_slurm_job.sh will recover via sacct — don't cancel it.
1415
if [ "${monitor_success:-0}" -ne 1 ] && [ -n "${job_id:-}" ]; then
15-
echo "Monitor exiting abnormally — cancelling SLURM job $job_id"
16-
scancel "$job_id" 2>/dev/null || true
16+
active_state=$(squeue -j "$job_id" -h -o '%T' 2>/dev/null | head -n1 | tr -d ' ' || echo "")
17+
if [ -n "$active_state" ]; then
18+
echo "Monitor exiting abnormally — cancelling SLURM job $job_id (state: $active_state)"
19+
scancel "$job_id" 2>/dev/null || true
20+
else
21+
echo "Monitor exiting abnormally — SLURM job $job_id already left queue, not cancelling"
22+
fi
1723
fi
1824
}
1925
trap cleanup EXIT
@@ -56,9 +62,11 @@ get_job_state() {
5662
}
5763

5864
# Check if a state is terminal (job is done, for better or worse)
65+
# PREEMPTED is intentionally excluded: with --requeue the job restarts under
66+
# the same job ID and we must keep monitoring rather than exiting early.
5967
is_terminal_state() {
6068
case "$1" in
61-
COMPLETED|FAILED|CANCELLED|CANCELLED+|TIMEOUT|OUT_OF_MEMORY|NODE_FAIL|BOOT_FAIL|DEADLINE|PREEMPTED|REVOKED)
69+
COMPLETED|FAILED|CANCELLED|CANCELLED+|TIMEOUT|OUT_OF_MEMORY|NODE_FAIL|BOOT_FAIL|DEADLINE|REVOKED)
6270
return 0 ;;
6371
*)
6472
return 1 ;;
@@ -74,7 +82,7 @@ while [ ! -f "$output_file" ]; do
7482
state=$(get_job_state "$job_id")
7583

7684
case "$state" in
77-
PENDING|CONFIGURING)
85+
PENDING|CONFIGURING|PREEMPTED)
7886
unknown_count=0
7987
sleep 5
8088
;;

.github/scripts/prebuild-case-optimization.sh

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#!/bin/bash
22

33
# Pre-builds all benchmark cases with --case-optimization.
4+
# No GPU hardware needed — compilation only.
45
# Can run in two modes:
56
# 1. Direct (Frontier login nodes): pass cluster/device/interface as args
6-
# 2. Inside SLURM (Phoenix): uses $job_device/$job_interface from submit.sh
7+
# 2. Inside SLURM (Phoenix): uses $job_device/$job_interface from submit-slurm-job.sh
78
# Usage: bash prebuild-case-optimization.sh [<cluster> <device> <interface>]
89

910
set -e
1011

11-
# Support both positional args (direct invocation) and env vars (SLURM via submit.sh)
12+
# Support both positional args (direct invocation) and env vars (SLURM)
1213
cluster="${1:-${job_cluster:-phoenix}}"
1314
job_device="${2:-$job_device}"
1415
job_interface="${3:-$job_interface}"
@@ -21,8 +22,18 @@ case "$cluster" in
2122
*) echo "ERROR: Unknown cluster '$cluster'"; exit 1 ;;
2223
esac
2324

25+
rm -rf build
26+
2427
. ./mfc.sh load -c "$flag" -m g
25-
source .github/scripts/gpu-opts.sh
28+
29+
# Set GPU build flags from interface — this is always a GPU build.
30+
# Don't use gpu-opts.sh since $job_device may be "cpu" when submitted
31+
# to a CPU SLURM partition (no GPU hardware needed for compilation).
32+
case "$job_interface" in
33+
acc) gpu_opts="--gpu acc" ;;
34+
omp) gpu_opts="--gpu mp" ;;
35+
*) echo "ERROR: prebuild requires gpu interface (acc or omp)"; exit 1 ;;
36+
esac
2637

2738
for case in benchmarks/*/case.py; do
2839
echo "=== Pre-building: $case ==="

.github/scripts/retry-build.sh

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,16 @@
11
#!/bin/bash
2-
# Provides retry_build(): 3-attempt loop with configurable cleanup.
3-
# Set RETRY_CLEAN_CMD to override cleanup (default: rm -rf build/staging build/install build/lock.yaml).
4-
# Set RETRY_VALIDATE_CMD to run a post-build validation; failure triggers a retry.
2+
# Provides retry_build(): 2-attempt loop.
3+
# On failure of attempt 1, nukes the entire build directory before attempt 2.
4+
# If RETRY_VALIDATE_CMD is set, runs it after a successful build; a non-zero
5+
# exit triggers the same nuke-and-retry, catching e.g. SIGILL from binaries
6+
# compiled on a different CPU architecture.
57
# Usage: source .github/scripts/retry-build.sh
68
# retry_build ./mfc.sh build -j 8 --gpu acc
7-
8-
# Try normal cleanup; if it fails, escalate to cache nuke.
9-
_retry_clean() {
10-
local clean_cmd="$1"
11-
if eval "$clean_cmd" 2>/dev/null; then
12-
return 0
13-
fi
14-
echo " Normal cleanup failed."
15-
if type _cache_nuke > /dev/null 2>&1; then
16-
echo " Escalating to NFS cache nuke..."
17-
_cache_nuke
18-
else
19-
echo " _cache_nuke not available, best-effort rm."
20-
rm -rf build/staging build/install build/lock.yaml 2>/dev/null || true
21-
fi
22-
}
9+
# RETRY_VALIDATE_CMD='./syscheck' retry_build ./mfc.sh build -j 8
2310

2411
retry_build() {
25-
local clean_cmd="${RETRY_CLEAN_CMD:-rm -rf build/staging build/install build/lock.yaml}"
12+
local max_attempts=2
2613
local validate_cmd="${RETRY_VALIDATE_CMD:-}"
27-
local max_attempts=3
2814
local attempt=1
2915
while [ $attempt -le $max_attempts ]; do
3016
echo "Build attempt $attempt of $max_attempts..."
@@ -33,8 +19,8 @@ retry_build() {
3319
if ! eval "$validate_cmd"; then
3420
echo "Post-build validation failed on attempt $attempt."
3521
if [ $attempt -lt $max_attempts ]; then
36-
echo "Cleaning and retrying in 5s..."
37-
_retry_clean "$clean_cmd"
22+
echo " Nuking build directory before retry..."
23+
rm -rf build 2>/dev/null || true
3824
sleep 5
3925
attempt=$((attempt + 1))
4026
continue
@@ -48,8 +34,8 @@ retry_build() {
4834
return 0
4935
fi
5036
if [ $attempt -lt $max_attempts ]; then
51-
echo "Build failed on attempt $attempt. Retrying in 30s..."
52-
_retry_clean "$clean_cmd"
37+
echo " Build failed — nuking build directory before retry..."
38+
rm -rf build 2>/dev/null || true
5339
sleep 30
5440
else
5541
echo "Build failed after $max_attempts attempts."

.github/scripts/run-tests-with-retry.sh

Lines changed: 0 additions & 34 deletions
This file was deleted.

.github/scripts/run_case_optimization.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ for case in "${benchmarks[@]}"; do
4444
rm -rf "$case_dir/D" "$case_dir/p_all" "$case_dir/restart_data"
4545

4646
# Build + run with --case-optimization, small grid, 10 timesteps
47-
if ./mfc.sh run "$case" --case-optimization $gpu_opts -n "$ngpus" -j "$(nproc)" -- --gbpp 1 --steps 10; then
47+
if ./mfc.sh run "$case" --case-optimization $gpu_opts -n "$ngpus" -j 8 -- --gbpp 1 --steps 10; then
4848
# Validate output
4949
if build/venv/bin/python3 .github/scripts/check_case_optimization_output.py "$case_dir"; then
5050
echo "PASS: $case_name"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/bash
2+
# Run monitor_slurm_job.sh and recover if the monitor is killed (e.g. SIGKILL
3+
# from the runner OS) before the SLURM job completes. When the monitor exits
4+
# non-zero, sacct is used to verify the job's actual final state; if the SLURM
5+
# job succeeded we exit 0 so the CI step is not falsely marked as failed.
6+
#
7+
# Usage: run_monitored_slurm_job.sh <job_id> <output_file>
8+
9+
set -euo pipefail
10+
11+
if [ $# -ne 2 ]; then
12+
echo "Usage: $0 <job_id> <output_file>"
13+
exit 1
14+
fi
15+
16+
job_id="$1"
17+
output_file="$2"
18+
19+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20+
21+
monitor_exit=0
22+
bash "$SCRIPT_DIR/monitor_slurm_job.sh" "$job_id" "$output_file" || monitor_exit=$?
23+
24+
if [ "$monitor_exit" -ne 0 ]; then
25+
echo "Monitor exited with code $monitor_exit; re-checking SLURM job $job_id final state..."
26+
# Give the SLURM epilog time to finalize if the job just finished
27+
sleep 30
28+
final_state=$(sacct -j "$job_id" -n -X -P -o State 2>/dev/null | head -n1 | cut -d'|' -f1 | tr -d ' ' || true)
29+
final_state="${final_state:-UNKNOWN}"
30+
final_exit=$(sacct -j "$job_id" -X --format=ExitCode --noheader --parsable2 2>/dev/null | head -n1 | tr -d ' ' || true)
31+
final_exit="${final_exit:-}"
32+
echo "Final SLURM state=$final_state exit=$final_exit"
33+
if [ "$final_state" = "COMPLETED" ] && [ "$final_exit" = "0:0" ]; then
34+
echo "SLURM job $job_id completed successfully despite monitor failure — continuing."
35+
else
36+
echo "ERROR: SLURM job $job_id did not complete successfully (state=$final_state exit=$final_exit)"
37+
exit 1
38+
fi
39+
fi

.github/scripts/run_parallel_benchmarks.sh

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ echo "=========================================="
2020
echo "Starting parallel benchmark jobs..."
2121
echo "=========================================="
2222

23+
# For Phoenix GPU benchmarks, select a consistent GPU partition before launching
24+
# both parallel jobs so PR and master always land on the same GPU type.
25+
if [ "$device" = "gpu" ] && [ "$cluster" = "phoenix" ]; then
26+
echo "Selecting Phoenix GPU partition for benchmark consistency..."
27+
# Require 2 nodes so both PR and master jobs can run concurrently.
28+
GPU_PARTITION_MIN_NODES=2 source "${SCRIPT_DIR}/select-gpu-partition.sh"
29+
BENCH_GPU_PARTITION="$SELECTED_GPU_PARTITION"
30+
export BENCH_GPU_PARTITION
31+
fi
32+
2333
# Run both jobs with monitoring using dedicated script from PR
2434
# Use stdbuf for line-buffered output and prefix each line for clarity
2535
(set -o pipefail; stdbuf -oL -eL bash "${SCRIPT_DIR}/submit_and_monitor_bench.sh" pr "$device" "$interface" "$cluster" 2>&1 | while IFS= read -r line; do echo "[PR] $line"; done) &
@@ -32,22 +42,26 @@ echo "Master job started in background (PID: $master_pid)"
3242

3343
echo "Waiting for both jobs to complete..."
3444

35-
# Wait and capture exit codes reliably
45+
# Wait and capture exit codes reliably.
46+
# Use `wait ... || exit=$?` to avoid set -e aborting on the first failure
47+
# (which would orphan the second job).
3648
pr_exit=0
3749
master_exit=0
3850

39-
wait "$pr_pid"
40-
pr_exit=$?
51+
wait "$pr_pid" || pr_exit=$?
4152
if [ "$pr_exit" -ne 0 ]; then
4253
echo "PR job exited with code: $pr_exit"
54+
echo "Last 50 lines of PR job log:"
55+
tail -n 50 "pr/bench-${device}-${interface}.out" 2>/dev/null || echo " Could not read PR log"
4356
else
4457
echo "PR job completed successfully"
4558
fi
4659

47-
wait "$master_pid"
48-
master_exit=$?
60+
wait "$master_pid" || master_exit=$?
4961
if [ "$master_exit" -ne 0 ]; then
5062
echo "Master job exited with code: $master_exit"
63+
echo "Last 50 lines of master job log:"
64+
tail -n 50 "master/bench-${device}-${interface}.out" 2>/dev/null || echo " Could not read master log"
5165
else
5266
echo "Master job completed successfully"
5367
fi
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/bash
2+
# Select the best available Phoenix GPU partition using sinfo.
3+
# Sources into caller: exports SELECTED_GPU_PARTITION.
4+
#
5+
# Priority order prefers partitions most likely to have availability.
6+
# V100 is last due to slower performance near the test time limit.
7+
# Falls back to gpu-l40s if no partition meets the idle node threshold.
8+
# RTX 6000 nodes are excluded (too slow for the test suite time limit).
9+
#
10+
# Optional: set GPU_PARTITION_MIN_NODES before sourcing to require a minimum
11+
# number of idle/mix nodes (e.g. GPU_PARTITION_MIN_NODES=2 for parallel bench jobs).
12+
#
13+
# Usage: source .github/scripts/select-gpu-partition.sh
14+
15+
_GPU_PARTITION_PRIORITY="gpu-l40s gpu-h200 gpu-h100 gpu-a100 gpu-v100"
16+
_GPU_PARTITION_FALLBACK="gpu-l40s"
17+
_GPU_PARTITION_MIN_NODES="${GPU_PARTITION_MIN_NODES:-1}"
18+
19+
SELECTED_GPU_PARTITION=""
20+
for _part in $_GPU_PARTITION_PRIORITY; do
21+
_idle=$(sinfo -p "$_part" --noheader -o "%t" 2>/dev/null | grep -cE "^(idle|mix)" || true)
22+
if [ "${_idle:-0}" -ge "$_GPU_PARTITION_MIN_NODES" ]; then
23+
SELECTED_GPU_PARTITION="$_part"
24+
echo "Selected GPU partition: $SELECTED_GPU_PARTITION ($_idle idle/mix nodes)"
25+
break
26+
fi
27+
done
28+
29+
if [ -z "$SELECTED_GPU_PARTITION" ]; then
30+
echo "WARNING: No idle GPU partition found; falling back to $_GPU_PARTITION_FALLBACK (may queue)"
31+
SELECTED_GPU_PARTITION="$_GPU_PARTITION_FALLBACK"
32+
fi
33+
34+
export SELECTED_GPU_PARTITION
35+
unset _GPU_PARTITION_PRIORITY _GPU_PARTITION_FALLBACK _GPU_PARTITION_MIN_NODES _part _idle

0 commit comments

Comments
 (0)