Skip to content

Commit 7ea6dd9

Browse files
authored
Merge branch 'master' into file-per-process-ib-markers
2 parents 9b52325 + cc20c94 commit 7ea6dd9

154 files changed

Lines changed: 1338 additions & 724 deletions

File tree

Some content is hidden

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

.github/scripts/check_coverage_map_health.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
"""Fail loudly if the committed coverage map is stale or under-covers. Used by coverage-health.yml."""
22
import datetime
3-
import subprocess
43
import sys
54
from pathlib import Path
65

76
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "toolchain"))
8-
from mfc.test.coverage import COVERAGE_MAP_PATH, load_map, map_health # noqa: E402
7+
from mfc.test.coverage import COVERAGE_MAP_PATH, load_map, map_health, run_git # noqa: E402
98
from mfc.test.cases import list_cases # noqa: E402 (returns the current test list)
109

1110
MAX_AGE_DAYS = 10
@@ -40,7 +39,7 @@ def verified_sha(cwd=None):
4039
caller must read that as undeterminable and fall back to the wall-clock age rule, not
4140
as a failure -- an absent ref is not evidence of a broken refresh.
4241
"""
43-
rev = subprocess.run(["git", "rev-parse", "--verify", "--quiet", f"{VERIFIED_REF}^{{commit}}"], capture_output=True, text=True, check=False, cwd=cwd)
42+
rev = run_git(["rev-parse", "--verify", "--quiet", f"{VERIFIED_REF}^{{commit}}"], cwd)
4443
return rev.stdout.strip() or None
4544

4645

@@ -53,10 +52,10 @@ def verified_after_last_change(git_sha, cwd=None):
5352
"""
5453
if not git_sha:
5554
return None
56-
last = subprocess.run(["git", "log", "-1", "--format=%H", "--", *COVERAGE_RELEVANT_PATHS], capture_output=True, text=True, check=False, cwd=cwd)
55+
last = run_git(["log", "-1", "--format=%H", "--", *COVERAGE_RELEVANT_PATHS], cwd)
5756
if last.returncode != 0 or not last.stdout.strip():
5857
return None # shallow clone or no such commit -> fall back to the age rule
59-
ancestor = subprocess.run(["git", "merge-base", "--is-ancestor", last.stdout.strip(), git_sha], capture_output=True, check=False, cwd=cwd)
58+
ancestor = run_git(["merge-base", "--is-ancestor", last.stdout.strip(), git_sha], cwd)
6059
return {0: True, 1: False}.get(ancestor.returncode) # anything else -> None (unknown sha, shallow history)
6160

6261

.github/scripts/ci-outage.sh

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

.github/scripts/classify-build-failure.sh

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

.github/scripts/monitor_slurm_job.sh

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ output_file="$2"
3535
echo "Submitted batch job $job_id"
3636
echo "Monitoring output file: $output_file"
3737

38+
# Put the one thing a reader needs on the run's summary page. Without this,
39+
# learning why a job failed means opening a log of tens of thousands of lines --
40+
# and an infrastructure fault looks exactly like a test failure until you do.
41+
# Silent when not running under Actions.
42+
ci_summary() {
43+
[ -n "${GITHUB_STEP_SUMMARY:-}" ] || return 0
44+
printf '%b\n' "$1" >> "$GITHUB_STEP_SUMMARY"
45+
}
46+
3847
# Robustly check SLURM job state using squeue with sacct fallback.
3948
# Returns the state string (PENDING, RUNNING, COMPLETED, FAILED, etc.)
4049
# or "UNKNOWN" if both commands fail.
@@ -213,8 +222,14 @@ while true; do
213222
sleep "$MFC_MONITOR_POLL_SECONDS"
214223
done
215224

216-
# Give tail a moment to flush the final lines, then stop streaming.
225+
# Give tail a moment to flush the final lines, then stop streaming. Whether it
226+
# was still alive decides how much needs reprinting below: if it streamed the
227+
# whole job, printing the file again just doubles every log.
217228
sleep 2
229+
streamed_ok=0
230+
if kill -0 "${tail_pid}" 2>/dev/null; then
231+
streamed_ok=1
232+
fi
218233
kill "${tail_pid}" 2>/dev/null || true
219234
tail_pid=""
220235

@@ -238,9 +253,20 @@ if [ -f "$output_file" ]; then
238253
done
239254
fi
240255

256+
# Reprint only what streaming may have missed. `tail -f` above already emitted
257+
# the whole file as it was written, so cat'ing it again duplicated every job's
258+
# output -- measured at 3 copies of each line on a GPU job, and 65,000 lines of
259+
# offload diagnostics repeated for a single fault. The reprint exists solely as
260+
# a safety net for a tail that died mid-job, so it is bounded when tail survived
261+
# and complete only when it did not.
241262
echo ""
242-
echo "=== Final output ==="
243-
cat "$output_file"
263+
if [ "${streamed_ok:-0}" -eq 1 ]; then
264+
echo "=== Final output (tail; the full log streamed above) ==="
265+
tail -n "${MFC_MONITOR_FINAL_LINES:-40}" "$output_file"
266+
else
267+
echo "=== Final output (streaming stopped early; reprinting in full) ==="
268+
cat "$output_file"
269+
fi
244270

245271
# Check exit status with sacct fallback
246272
exit_code=""
@@ -267,26 +293,32 @@ if [ -z "$exit_code" ]; then
267293
exit 1
268294
fi
269295

270-
# Infrastructure verdicts from the in-allocation preflight come back as the
271-
# job's own exit code. Relay them verbatim: flattening them to 1 would leave the
272-
# submit wrapper unable to tell "this node is unusable" (exclude it and try
273-
# again) from "the tests failed" (report it).
296+
# The preflight's node-fault verdict comes back as the job's own exit code.
297+
# Relay it verbatim: flattening it to 1 would leave the submit wrapper unable to
298+
# tell "this node is unusable" (exclude it and try again) from "the tests
299+
# failed" (report it).
300+
faulted_node=$(grep -oE 'MFC_FAULT_NODE=[^ ]+' "$output_file" 2>/dev/null | tail -n1 | cut -d= -f2 || true)
301+
274302
case "$exit_code" in
275303
77:*)
276304
echo "Job $job_id failed preflight: the node is unusable — signaling caller to exclude it and resubmit."
305+
ci_summary "### :warning: Infrastructure fault — not a code or test failure\n\nNode \`${faulted_node:-unknown}\` could not run MFC (job \`$job_id\`). It is excluded and the job resubmitted elsewhere.\n"
277306
monitor_success=1
278307
exit 77
279308
;;
280-
78:*)
281-
echo "Job $job_id skipped: a cluster-wide outage is already recorded."
282-
monitor_success=1
283-
exit 78
284-
;;
285309
esac
286310

287311
# Check if job succeeded
288312
if [ "$exit_code" != "0:0" ]; then
289313
echo "ERROR: Job $job_id failed with exit code $exit_code"
314+
# A GPU memory fault explains itself in a block the test harness prints; lift
315+
# it onto the summary page so the faulting kernel and source line are visible
316+
# without opening the log at all.
317+
if grep -q 'GPU fault summary' "$output_file" 2>/dev/null; then
318+
ci_summary "### GPU memory fault\n\n\`\`\`\n$(grep -A6 'GPU fault summary' "$output_file" | head -8 | sed 's/`/'"'"'/g')\n\`\`\`\n"
319+
else
320+
ci_summary "### Job \`$job_id\` failed (exit $exit_code)\n\n\`\`\`\n$(tail -n 15 "$output_file" | sed 's/`/'"'"'/g')\n\`\`\`\n"
321+
fi
290322
exit 1
291323
fi
292324

0 commit comments

Comments
 (0)