Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
20cac31
ci: add three-layer workflow validation
richardoo-707 Sep 21, 2026
6a24503
ci: trigger layered workflow validation
richardoo-707 Sep 21, 2026
9581d63
ci: fix layered validation failures
richardoo-707 Sep 21, 2026
dedf33c
ci: remove validation-only push triggers
richardoo-707 Sep 21, 2026
2c1d55a
ci: trigger layer 3 validation
richardoo-707 Sep 22, 2026
003bba7
ci: remove layer 3 validation trigger
richardoo-707 Sep 22, 2026
aa98c62
ci: retry GPU layers when capacity is idle
richardoo-707 Sep 22, 2026
4d0f379
ci: make hourly GPU probe lightweight
richardoo-707 Sep 22, 2026
624d3e5
ci: remove GPU monitor validation trigger
richardoo-707 Sep 22, 2026
1581c44
ci: make GPU capacity probe self-contained
richardoo-707 Sep 23, 2026
6f2ca60
ci: trigger self-contained GPU probe validation
richardoo-707 Sep 23, 2026
08c413e
ci: fix layered GPU batch compatibility
richardoo-707 Sep 23, 2026
a2cba07
ci: make layered GPU suites hermetic
richardoo-707 Sep 24, 2026
0d3a7d6
ci: address layered GPU suite failures
richardoo-707 Sep 29, 2026
b922d91
ci: validate layer 3 directly
richardoo-707 Sep 29, 2026
9c3a7e2
ci: handle ConvNeXt lazy init compatibility
richardoo-707 Sep 29, 2026
13f6b73
ci: address remaining layer 3 failures
richardoo-707 Oct 4, 2026
9096055
ci: isolate long Qwen2 GPU coverage
richardoo-707 Oct 4, 2026
641cda4
fix: resolve layered GPU CI runtime regressions
richardoo-707 Oct 8, 2026
f7762b5
Merge main into ci/three-layer-workflow-validation
richardoo-707 Oct 10, 2026
72d4aab
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
self-hosted-runner:
labels:
- colossalai-e1-h20
102 changes: 102 additions & 0 deletions .github/scripts/ci/check_idle_gpus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""Report idle H20 capacity for the hourly layered-CI gate."""

import argparse
import json
import os
import socket
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path

from run_gpu_batch import find_idle, parse_pool, query_gpus


def utcnow():
return datetime.now(timezone.utc).isoformat()


def readiness(idle_count, layer2_required=2, layer3_required=8):
if idle_count < 0 or layer2_required < 1 or layer3_required < layer2_required:
raise ValueError("Invalid GPU readiness thresholds")
return {
"layer2_ready": idle_count >= layer2_required,
"layer3_ready": idle_count >= layer3_required,
}


def append_outputs(path, values):
if path is None:
return
with path.open("a", encoding="utf-8") as output:
for key, value in values.items():
if isinstance(value, bool):
value = str(value).lower()
output.write(f"{key}={value}\n")


def append_summary(path, result):
if path is None:
return
with path.open("a", encoding="utf-8") as summary:
summary.write("## Hourly GPU capacity gate\n\n")
summary.write(f"- Host: `{result['host']}`\n")
summary.write(f"- Runner: `{result['runner']}`\n")
summary.write(f"- Idle GPU indices: `{result['idle_gpu_indices']}`\n")
summary.write(f"- Layer 2 ready (needs 2): `{str(result['layer2_ready']).lower()}`\n")
summary.write(f"- Layer 3 ready (needs 8): `{str(result['layer3_ready']).lower()}`\n")


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--layer2-required", type=int, default=2)
parser.add_argument("--layer3-required", type=int, default=8)
parser.add_argument(
"--lock",
type=Path,
default=Path(os.environ.get("CI_GPU_LOCK", "/tmp/colossalai-ci-gpu.lock")),
)
parser.add_argument("--github-output", type=Path, default=os.environ.get("GITHUB_OUTPUT"))
parser.add_argument("--summary", type=Path, default=os.environ.get("GITHUB_STEP_SUMMARY"))
args = parser.parse_args()

if os.name != "posix":
raise RuntimeError("GPU capacity checks require a Linux runner")
import fcntl

args.lock.parent.mkdir(parents=True, exist_ok=True)
result = {
"host": socket.gethostname().split(".")[0],
"runner": os.environ.get("RUNNER_NAME"),
"checked_at": utcnow(),
}

try:
with args.lock.open("w") as lock:
fcntl.flock(lock, fcntl.LOCK_EX)
inventory, processes = query_gpus()
idle = find_idle(inventory, processes, parse_pool(os.environ.get("COLOSSAL_GPU_POOL")))
result["idle_gpu_count"] = len(idle)
result["idle_gpu_indices"] = [index for index, _ in idle]
result.update(readiness(len(idle), args.layer2_required, args.layer3_required))
append_outputs(
args.github_output,
{
"idle_gpu_count": result["idle_gpu_count"],
"layer2_ready": result["layer2_ready"],
"layer3_ready": result["layer3_ready"],
},
)
append_summary(args.summary, result)
except (RuntimeError, OSError, ValueError, subprocess.SubprocessError) as error:
result["error"] = str(error)
print(json.dumps(result, indent=2), flush=True)
return 1

print(json.dumps(result, indent=2), flush=True)
return 0


if __name__ == "__main__":
sys.exit(main())
Loading
Loading