236 lines
8.1 KiB
Bash
Executable File
236 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# verify_submission.sh — 竞赛提交前的完整验证
|
|
#
|
|
# 在真机上运行:
|
|
# cd /home/dylan/project_6
|
|
# bash verify_submission.sh
|
|
#
|
|
# 检查项:
|
|
# 1. Dockerfile语法
|
|
# 2. patch_ops.sh可执行 + 引用的文件全部存在
|
|
# 3. CCCL preload编译链完整(头文件+源文件+build脚本)
|
|
# 4. computility-run.yaml路径与build输出匹配
|
|
# 5. prebuilt .so文件完整性(SHA256)
|
|
# 6. qwen3_5.py imports的corex模块全部有对应.so或build脚本
|
|
# 7. Docker context大小(不要超过平台限制)
|
|
# 8. 单卡冒烟测试(如果有GPU)
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
WARN=0
|
|
|
|
check() {
|
|
local name=$1; shift
|
|
if "$@" >/dev/null 2>&1; then
|
|
echo " ✓ $name"
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ $name"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
}
|
|
|
|
warn() {
|
|
echo " △ $1"
|
|
WARN=$((WARN+1))
|
|
}
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$ROOT"
|
|
|
|
echo "=== 1. 文件结构 ==="
|
|
check "Dockerfile存在" test -f Dockerfile
|
|
check "computility-run.yaml存在" test -f computility-run.yaml
|
|
check "patch_ops.sh存在" test -f qwen3_6_scripts/patch_ops.sh
|
|
check "patch_ops.sh可执行" test -x qwen3_6_scripts/patch_ops.sh
|
|
check ".dockerignore存在" test -f .dockerignore
|
|
|
|
echo ""
|
|
echo "=== 2. CCCL Preload编译链 ==="
|
|
check "build脚本存在" test -f qwen3_6_scripts/cccl_preload/build_cccl_preload.sh
|
|
check "源文件存在" test -f qwen3_6_scripts/cccl_preload/cccl_allocator_preload.cu
|
|
check "CCCL头文件目录存在" test -d qwen3_6_scripts/cccl_preload/include/cub
|
|
check "libcudacxx头文件存在" test -d qwen3_6_scripts/cccl_preload/include/cuda
|
|
|
|
CCCL_HEADERS=$(find qwen3_6_scripts/cccl_preload/include -type f 2>/dev/null | wc -l)
|
|
if [[ "$CCCL_HEADERS" -ge 280 ]]; then
|
|
echo " ✓ CCCL头文件数量: $CCCL_HEADERS (≥280)"
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ CCCL头文件数量: $CCCL_HEADERS (期望≥280)"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
|
|
# 检查关键头文件
|
|
check "cub/util_allocator.cuh" test -f qwen3_6_scripts/cccl_preload/include/cub/util_allocator.cuh
|
|
check "cub/config.cuh" test -f qwen3_6_scripts/cccl_preload/include/cub/config.cuh
|
|
check "cuda/__cccl_config" test -f qwen3_6_scripts/cccl_preload/include/cuda/__cccl_config
|
|
check "nv/target" test -f qwen3_6_scripts/cccl_preload/include/nv/target
|
|
|
|
echo ""
|
|
echo "=== 3. patch_ops.sh → CCCL preload 调用链 ==="
|
|
if grep -q "cccl_preload/build_cccl_preload.sh" qwen3_6_scripts/patch_ops.sh; then
|
|
echo " ✓ patch_ops.sh调用新版build脚本"
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ patch_ops.sh未调用cccl_preload/build_cccl_preload.sh"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
|
|
# 检查旧文件是否残留
|
|
if [[ -f qwen3_6_scripts/cccl_preload_allocator.cu ]]; then
|
|
echo " ✗ 旧mock文件残留: cccl_preload_allocator.cu"
|
|
FAIL=$((FAIL+1))
|
|
else
|
|
echo " ✓ 旧mock文件已清理"
|
|
PASS=$((PASS+1))
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== 4. computility-run.yaml 路径匹配 ==="
|
|
YAML_PRELOAD=$(grep -A1 "LD_PRELOAD" computility-run.yaml | grep "value:" | awk '{print $2}')
|
|
if [[ -n "$YAML_PRELOAD" ]]; then
|
|
echo " ✓ LD_PRELOAD已配置: $YAML_PRELOAD"
|
|
PASS=$((PASS+1))
|
|
# 检查路径与build输出一致
|
|
BUILD_OUTPUT_DIR=$(grep "build_cccl_preload.sh" qwen3_6_scripts/patch_ops.sh | grep -oP '/workspace/\S+' | head -1 | tr -d ';')
|
|
EXPECTED_SO="${BUILD_OUTPUT_DIR}/libcccl_allocator.so"
|
|
if [[ "$YAML_PRELOAD" == "$EXPECTED_SO" || "$YAML_PRELOAD" == "/workspace/qwen3_6_scripts/libcccl_allocator.so" ]]; then
|
|
echo " ✓ 路径匹配build输出"
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ 路径不匹配: yaml=$YAML_PRELOAD expected=$EXPECTED_SO"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
else
|
|
echo " ✗ computility-run.yaml缺少LD_PRELOAD"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
|
|
# 检查CCCL_ALLOC_DISABLE
|
|
if grep -q "CCCL_ALLOC_DISABLE" computility-run.yaml; then
|
|
echo " ✓ CCCL_ALLOC_DISABLE可控"
|
|
PASS=$((PASS+1))
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== 5. Prebuilt .so 完整性 ==="
|
|
PREBUILT_DIR="qwen3_6_scripts/prebuilt/corex-3.2.3-ivcore10"
|
|
if [[ -f "${PREBUILT_DIR}/SHA256SUMS" ]]; then
|
|
EXPECTED=$(wc -l < "${PREBUILT_DIR}/SHA256SUMS")
|
|
ACTUAL=$(ls "${PREBUILT_DIR}"/*.so 2>/dev/null | wc -l)
|
|
if [[ "$ACTUAL" -ge "$EXPECTED" ]]; then
|
|
echo " ✓ prebuilt .so数量: $ACTUAL (manifest expects $EXPECTED)"
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ prebuilt .so数量不足: $ACTUAL < $EXPECTED"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
# 如果有sha256sum工具, 验证checksum
|
|
if command -v sha256sum &>/dev/null; then
|
|
if (cd "$PREBUILT_DIR" && sha256sum --status --check SHA256SUMS 2>/dev/null); then
|
|
echo " ✓ SHA256校验通过"
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ SHA256校验失败"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
fi
|
|
else
|
|
echo " △ SHA256SUMS不存在, 跳过校验"
|
|
WARN=$((WARN+1))
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== 6. qwen3_5.py corex imports vs prebuilt ==="
|
|
IMPORTS=$(grep "from vllm import corex_" qwen3_6_scripts/qwen3_5.py 2>/dev/null | sed 's/.*import //' | sed 's/ as.*//' | sort -u)
|
|
for mod in $IMPORTS; do
|
|
SO_FILE="${PREBUILT_DIR}/${mod}.so"
|
|
BUILD_SCRIPT="qwen3_6_scripts/build_${mod}.sh"
|
|
if [[ -f "$SO_FILE" ]]; then
|
|
echo " ✓ $mod → prebuilt .so"
|
|
PASS=$((PASS+1))
|
|
elif [[ -f "$BUILD_SCRIPT" ]]; then
|
|
echo " △ $mod → build脚本存在 (docker内编译)"
|
|
WARN=$((WARN+1))
|
|
else
|
|
echo " ✗ $mod → 无.so也无build脚本"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
echo "=== 7. Docker context大小 ==="
|
|
# 排除.git和大文件
|
|
if [[ -f .dockerignore ]]; then
|
|
# 粗略估算
|
|
CONTEXT_SIZE=$(du -sh --exclude='.git' --exclude='cccl_upstream' --exclude='upstream_ref' --exclude='*.zip' --exclude='vllm' --exclude='ixformer_sdk' qwen3_6_scripts/ computility-run.yaml Dockerfile 2>/dev/null | tail -1 | awk '{print $1}')
|
|
echo " 核心文件大小: ~$CONTEXT_SIZE"
|
|
echo " (.dockerignore应排除cccl_upstream/, upstream_ref/, vllm/, *.zip等)"
|
|
fi
|
|
|
|
# 检查.dockerignore是否排除大目录
|
|
if [[ -f .dockerignore ]]; then
|
|
for dir in cccl_upstream upstream_ref vllm ixformer_sdk "*.zip"; do
|
|
if grep -q "$dir" .dockerignore 2>/dev/null; then
|
|
echo " ✓ .dockerignore排除: $dir"
|
|
else
|
|
warn ".dockerignore未排除: $dir (可能导致docker context过大)"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== 8. 单卡冒烟测试 ==="
|
|
if command -v ixsmi &>/dev/null || command -v nvidia-smi &>/dev/null; then
|
|
echo " 检测到GPU, 运行基础验证..."
|
|
if python3 -c "import torch; assert torch.cuda.is_available(); print(f' ✓ PyTorch CUDA: {torch.cuda.get_device_name(0)}')" 2>/dev/null; then
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ PyTorch CUDA不可用"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
|
|
# 测试CCCL preload编译
|
|
if [[ -f qwen3_6_scripts/cccl_preload/build_cccl_preload.sh ]]; then
|
|
echo " 尝试编译CCCL preload .so..."
|
|
if bash qwen3_6_scripts/cccl_preload/build_cccl_preload.sh /tmp 2>/dev/null; then
|
|
if [[ -s /tmp/libcccl_allocator.so ]]; then
|
|
echo " ✓ CCCL preload编译成功"
|
|
PASS=$((PASS+1))
|
|
# 测试加载
|
|
if LD_PRELOAD=/tmp/libcccl_allocator.so python3 -c "import torch; x=torch.zeros(1024,device='cuda'); del x; print(' ✓ LD_PRELOAD加载正常')" 2>/dev/null; then
|
|
PASS=$((PASS+1))
|
|
else
|
|
echo " ✗ LD_PRELOAD加载失败"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
rm -f /tmp/libcccl_allocator.so
|
|
else
|
|
echo " ✗ 编译产物为空"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
else
|
|
echo " ✗ CCCL preload编译失败"
|
|
FAIL=$((FAIL+1))
|
|
fi
|
|
fi
|
|
else
|
|
echo " (无GPU, 跳过)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "==========================================="
|
|
echo " PASS: $PASS FAIL: $FAIL WARN: $WARN"
|
|
echo "==========================================="
|
|
|
|
if [[ "$FAIL" -gt 0 ]]; then
|
|
echo ""
|
|
echo "⚠ 有 $FAIL 个检查失败, 提交前请修复!"
|
|
exit 1
|
|
else
|
|
echo ""
|
|
echo "✓ 全部检查通过, 可以提交"
|
|
exit 0
|
|
fi
|