Repository navigation
Atomesh Accuracy Validation #16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Atomesh Accuracy Validation | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'atom/mesh/**' | |
| - '.github/workflows/atomesh-accuracy-validation.yaml' | |
| - '.github/scripts/accuracy_to_dashboard.py' | |
| - '.github/benchmark/models_accuracy.json' | |
| pull_request: | |
| branches: [main] # Triggers on PRs targeting `main` | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| paths: | |
| - 'atom/mesh/**' | |
| - '.github/workflows/atomesh-accuracy-validation.yaml' | |
| - '.github/scripts/accuracy_to_dashboard.py' | |
| - '.github/benchmark/models_accuracy.json' | |
| schedule: | |
| # Nightly at 00:00 Beijing time (16:00 UTC) | |
| - cron: '0 16 * * *' | |
| workflow_dispatch: | |
| inputs: | |
| aiter_branch: | |
| description: 'ROCm/aiter branch to build inside the CI image' | |
| required: false | |
| default: 'main' | |
| type: string | |
| atom_base_image: | |
| description: 'Docker image used as the ATOM test base image' | |
| required: false | |
| default: 'rocm/atom-dev:latest' | |
| type: string | |
| concurrency: | |
| # Keep scheduled main runs from blocking push-triggered validation. | |
| group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} | |
| cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} | |
| env: | |
| ATOM_BASE_IMAGE: ${{ github.event_name == 'workflow_dispatch' && inputs.atom_base_image || 'rocm/atom-dev:latest' }} | |
| ATOM_PYTHON_TAG: "cp312" | |
| GITHUB_REPO_URL: ${{ github.event.pull_request.head.repo.clone_url || 'https://github.com/ROCm/ATOM.git' }} | |
| GITHUB_COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.event.head_commit.id || github.sha }} | |
| # workflow_dispatch: inputs.aiter_branch; otherwise main (matches previous default-branch shallow clone) | |
| AITER_GIT_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.aiter_branch || 'main' }} | |
| jobs: | |
| check-signal: | |
| if: ${{ !github.event.pull_request || github.event.pull_request.draft == false }} | |
| name: Check Pre Checkin Signal | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: read | |
| steps: | |
| - name: Checkout ATOM repo | |
| if: ${{ github.event_name != 'workflow_dispatch' }} | |
| uses: actions/checkout@v6 | |
| - name: Wait for Pre Checkin workflow | |
| if: ${{ github.event_name != 'workflow_dispatch' }} | |
| run: bash ./.github/scripts/check_signal.sh | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_SHA: ${{ github.sha }} | |
| download_aiter_wheel: | |
| if: ${{ needs.check-signal.result == 'success' && (!github.event.pull_request || github.event.pull_request.draft == false) }} | |
| needs: [check-signal] | |
| name: Download aiter wheel | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Prefer latest main aiter wheel manifest and fallback to artifact | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: bash .github/scripts/download_aiter_wheel.sh | |
| - name: Upload aiter wheel | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: aiter-whl | |
| path: aiter-whl/amd_aiter*.whl | |
| retention-days: 7 | |
| load-test-models: | |
| name: Load test model configs | |
| runs-on: ubuntu-latest | |
| outputs: | |
| models_json: ${{ steps.load.outputs.models_json }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - id: load | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| python3 << 'PY' | |
| import json, os | |
| event = os.environ["EVENT_NAME"] | |
| # Atomesh standalone validates a small representative subset only. | |
| # Keep this whitelist local; full ATOM accuracy owns test_level. | |
| level_map = {"schedule": "nightly", "workflow_dispatch": "nightly", "push": "main"} | |
| current = level_map.get(event, "pr") | |
| allowed = {"pr": {"pr"}, "main": {"pr", "main"}, "nightly": {"pr", "main", "nightly"}}[current] | |
| models = json.load(open(".github/benchmark/models_accuracy.json", encoding="utf-8")) | |
| # NOTE: Meta-Llama-3-8B-Instruct was this whitelist's only "pr" entry | |
| # and has been removed from models_accuracy.json, so atomesh | |
| # standalone currently validates nothing on a pull request. Promoting | |
| # a replacement changes what every atomesh PR pays for, so it is left | |
| # to the job owner rather than decided here. | |
| atomesh_levels = { | |
| "DeepSeek-R1-0528": "main", | |
| "DeepSeek-V4-Pro MTP": "nightly", | |
| "gpt-oss-120b": "nightly", | |
| } | |
| filtered = [m for m in models if atomesh_levels.get(m["model_name"], "skip") in allowed] | |
| with open(os.environ["GITHUB_OUTPUT"], "a") as f: | |
| f.write(f"models_json={json.dumps(filtered)}\n") | |
| print(f"Event={event} level={current}: {len(filtered)}/{len(models)} models") | |
| print(f"{'Model':<45} {'Atomesh':<10} {'ATOM':<10} {'Runner'}") | |
| print("-" * 80) | |
| for m in models: | |
| enabled = "✓" if m in filtered else "·" | |
| print( | |
| f" {enabled} {m['model_name']:<43} " | |
| f"{atomesh_levels.get(m['model_name'],'skip'):<10} " | |
| f"{m.get('test_level','?'):<10} {m['runner']}" | |
| ) | |
| PY | |
| atomesh-test: | |
| needs: [download_aiter_wheel, load-test-models] | |
| name: Accuracy | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: ${{ fromJson(needs.load-test-models.outputs.models_json) }} | |
| if: ${{ !github.event.pull_request || github.event.pull_request.draft == false }} | |
| runs-on: ${{ matrix.runner }} | |
| env: | |
| CONTAINER_NAME: atomesh_test_${{ strategy.job-index }} | |
| USE_ATOMESH_ENTRYPOINTS: 1 | |
| ATOM_SERVER_PORT: 8000 | |
| steps: | |
| - name: Kill all Docker containers and clean up workspace | |
| if: matrix.runner == 'atom-mi355-8gpu.predownload' || matrix.runner == 'linux-atom-do-mi350x-8' | |
| run: | | |
| echo "=== Cleaning up containers on $(hostname) ===" | |
| containers=$(docker ps -q) | |
| if [ -n "$containers" ]; then | |
| docker kill $containers || true | |
| fi | |
| docker run --rm -v "${GITHUB_WORKSPACE:-$PWD}":/workspace -w /workspace --privileged rocm/pytorch:latest bash -lc "ls -la /workspace/ && find /workspace -mindepth 1 -delete" || true | |
| - name: Show Docker containers | |
| if: matrix.runner == 'atom-mi355-8gpu.predownload' || matrix.runner == 'linux-atom-do-mi350x-8' | |
| run: docker ps -a | |
| - name: Show ROCm memory usage | |
| if: matrix.runner == 'atom-mi355-8gpu.predownload' || matrix.runner == 'linux-atom-do-mi350x-8' | |
| run: rocm-smi --showmemuse | |
| - name: Show ROCm GPU processes | |
| if: matrix.runner == 'atom-mi355-8gpu.predownload' || matrix.runner == 'linux-atom-do-mi350x-8' | |
| run: rocm-smi --showpidgpus | |
| - name: Checkout ATOM repo | |
| uses: actions/checkout@v6 | |
| - name: Docker Login | |
| if: ${{ !github.event.pull_request.head.repo.fork }} | |
| uses: ./.github/actions/docker-auth | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Resolve immutable native dashboard image | |
| if: ${{ github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule') }} | |
| env: | |
| DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} | |
| DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} | |
| run: | | |
| set -euo pipefail | |
| if RESOLUTION_JSON="$( | |
| python3 .github/scripts/resolve_atom_image.py \ | |
| --repository rocm/atom-dev \ | |
| --reference-tag latest \ | |
| --image-family native | |
| )"; then | |
| RESOLVED_ATOM_IMAGE="$( | |
| RESOLUTION_JSON="${RESOLUTION_JSON}" python3 - <<'PY' | |
| import json | |
| import os | |
| resolution = json.loads(os.environ["RESOLUTION_JSON"]) | |
| print(resolution["resolved_image"]) | |
| PY | |
| )" | |
| echo "Resolved native dashboard image: ${RESOLVED_ATOM_IMAGE}" | |
| else | |
| echo "::error::Failed to resolve ${ATOM_BASE_IMAGE} to an immutable reference for dashboard-uploading native runs." | |
| exit 1 | |
| fi | |
| echo "RESOLVED_ATOM_BASE_IMAGE=${RESOLVED_ATOM_IMAGE}" >> "$GITHUB_ENV" | |
| echo "ATOM_DASHBOARD_DOCKER_IMAGE=${RESOLVED_ATOM_IMAGE}" >> "$GITHUB_ENV" | |
| - name: Pull immutable native dashboard image | |
| if: ${{ github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule') }} | |
| run: | | |
| echo "Pulling immutable native dashboard image: ${RESOLVED_ATOM_BASE_IMAGE}" | |
| docker pull "${RESOLVED_ATOM_BASE_IMAGE}" | |
| - name: Generate Dockerfile for forked repo | |
| if: ${{ github.event.pull_request.head.repo.fork }} | |
| run: | | |
| cat <<EOF > Dockerfile.mod | |
| FROM ${{ env.ATOM_BASE_IMAGE }} | |
| RUN pip install -U lm-eval[api] | |
| RUN pip show lm-eval || true | |
| RUN pip install hf_transfer | |
| RUN pip show hf_transfer || true | |
| RUN echo "=== Aiter version BEFORE uninstall ===" && pip show amd-aiter || true | |
| RUN pip uninstall -y amd-aiter | |
| RUN pip install --upgrade "pybind11>=3.0.1" | |
| RUN pip show pybind11 | |
| RUN rm -rf /app/aiter-test | |
| RUN git clone --filter=blob:none -b ${{ env.AITER_GIT_REF }} https://github.com/ROCm/aiter.git /app/aiter-test && \\ | |
| cd /app/aiter-test && \\ | |
| git submodule sync && git submodule update --init --recursive && \\ | |
| MAX_JOBS=64 PREBUILD_KERNELS=0 GPU_ARCHS=gfx950 python3 setup.py develop | |
| RUN echo "=== Aiter version AFTER installation ===" && pip show amd-aiter || true | |
| RUN echo "=== ATOM version BEFORE uninstall ===" && pip show atom || true | |
| RUN pip uninstall -y atom | |
| RUN rm -rf /app/ATOM | |
| ARG RUST_VERSION="1.94.0" | |
| RUN if ! command -v cargo >/dev/null 2>&1; then \\ | |
| echo "=== Installing Rust toolchain for atomesh build ===" && \\ | |
| apt-get update && \\ | |
| apt --fix-broken install -y && \\ | |
| apt-get install -y --no-install-recommends curl build-essential pkg-config libssl-dev protobuf-compiler libprotobuf-dev && \\ | |
| rm -rf /var/lib/apt/lists/* && \\ | |
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \\ | |
| | sh -s -- -y --default-toolchain "\${RUST_VERSION}" --profile minimal && \\ | |
| . "\$HOME/.cargo/env" && \\ | |
| rustc --version && cargo --version; \\ | |
| fi | |
| ENV PATH="/root/.cargo/bin:\$PATH" | |
| RUN git clone ${{ env.GITHUB_REPO_URL }} /app/ATOM && \\ | |
| cd /app/ATOM && \\ | |
| git checkout ${{ env.GITHUB_COMMIT_SHA }} && \\ | |
| ATOM_MESH_BUILD=1 python -m pip install -e . | |
| RUN echo "=== ATOM version AFTER installation ===" && pip show atom || true | |
| EOF | |
| - name: Download aiter wheel | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: aiter-whl | |
| path: /tmp/aiter-whl | |
| - name: Set HF token for predownload runner | |
| if: matrix.runner == 'atom-mi355-8gpu.predownload' || matrix.runner == 'linux-atom-do-mi350x-8' | |
| run: echo "HF_TOKEN=${HF_TOKEN:-${{ secrets.AMD_HF_TOKEN }}}" >> "$GITHUB_ENV" | |
| - name: Start CI container | |
| uses: ./.github/actions/setup-gpu-container | |
| with: | |
| container-name: ${{ env.CONTAINER_NAME }} | |
| base-image: ${{ env.ATOM_BASE_IMAGE }} | |
| resolved-image: ${{ env.RESOLVED_ATOM_BASE_IMAGE }} | |
| runner: ${{ matrix.runner }} | |
| env-vars: ${{ matrix.env_vars }} | |
| hf-token: ${{ env.HF_TOKEN }} | |
| dashboard-image: ${{ env.ATOM_DASHBOARD_DOCKER_IMAGE }} | |
| extra-run-flags: -e USE_ATOMESH_ENTRYPOINTS=${{ env.USE_ATOMESH_ENTRYPOINTS }} -e ATOM_SERVER_PORT=${{ env.ATOM_SERVER_PORT }} | |
| - name: Check shm size | |
| run: | | |
| docker exec "$CONTAINER_NAME" df -h /dev/shm | |
| - name: Collect GPU info (inside container) | |
| id: gpu-info | |
| run: bash .github/scripts/collect_gpu_info.sh "$CONTAINER_NAME" docker "${{ matrix.runner }}" | |
| - name: Install aiter from wheel | |
| run: bash .github/scripts/install_aiter_wheel.sh | |
| - name: Install ATOM and dependencies | |
| run: | | |
| docker exec "$CONTAINER_NAME" bash -lc " | |
| set -euo pipefail | |
| pip install --timeout 60 --retries 10 -U 'lm-eval[api]' | |
| pip install --timeout 60 --retries 10 hf_transfer | |
| pip install --timeout 60 --retries 10 --upgrade 'pybind11>=3.0.1' | |
| if ! command -v cargo >/dev/null 2>&1; then | |
| echo '=== Installing Rust toolchain for atomesh build ===' | |
| RUST_VERSION='1.94.0' | |
| apt-get update | |
| apt --fix-broken install -y | |
| apt-get install -y --no-install-recommends curl build-essential pkg-config libssl-dev protobuf-compiler libprotobuf-dev | |
| rm -rf /var/lib/apt/lists/* | |
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | |
| | sh -s -- -y --default-toolchain \"\$RUST_VERSION\" --profile minimal | |
| . \"\$HOME/.cargo/env\" | |
| fi | |
| export PATH=\"\$HOME/.cargo/bin:\$PATH\" | |
| rustc --version | |
| cargo --version | |
| echo '=== Installing ATOM ===' | |
| cd /workspace | |
| git config --global --add safe.directory /workspace | |
| ATOM_MESH_BUILD=1 python -m pip install -e . | |
| echo '=== Installed package versions ===' | |
| pip show amd-aiter | grep -E '^(Name|Version):' | |
| pip show atom | grep -E '^(Name|Version):' | |
| pip show triton | grep -E '^(Name|Version):' | |
| pip show torch | grep -E '^(Name|Version):' | |
| " | |
| - name: Download models | |
| timeout-minutes: 150 | |
| run: | | |
| set -euo pipefail | |
| if [ -d "/models" ]; then | |
| model_dir="/models/${{ matrix.model_path }}" | |
| echo "/models directory found, checking cache and lock-protected download for ${model_dir}" | |
| if ! docker exec \ | |
| -e HF_TOKEN="${HF_TOKEN:-}" \ | |
| -e MODEL_ID="${{ matrix.model_path }}" \ | |
| -e TARGET_DIR="${model_dir}" \ | |
| -e MODEL_DOWNLOAD_TIMEOUT="${MODEL_DOWNLOAD_TIMEOUT}" \ | |
| -e MODEL_LOCK_WAIT_SECONDS="${MODEL_LOCK_WAIT_SECONDS}" \ | |
| -e MODEL_LOCK_POLL_INTERVAL="${MODEL_LOCK_POLL_INTERVAL}" \ | |
| -e MODEL_PROGRESS_INTERVAL="${MODEL_PROGRESS_INTERVAL}" \ | |
| "$CONTAINER_NAME" bash -lc 'bash /workspace/.github/scripts/download_model_with_lock.sh "$MODEL_ID" "$TARGET_DIR"'; then | |
| echo "Model download failed for '${{ matrix.model_path }}'. Aborting." | |
| exit 1 | |
| fi | |
| else | |
| echo "/models directory not found, skipping model download" | |
| fi | |
| env: | |
| MODEL_DOWNLOAD_TIMEOUT: "30m" | |
| MODEL_LOCK_WAIT_SECONDS: "1800" | |
| MODEL_LOCK_POLL_INTERVAL: "30" | |
| MODEL_PROGRESS_INTERVAL: "60" | |
| - name: Run ATOM simple inference | |
| # Skip simple inference; accuracy test already validates correctness | |
| if: false | |
| timeout-minutes: 30 | |
| run: | | |
| # Run the inference and capture output | |
| set -euo pipefail | |
| echo "" | |
| echo "========== Running test ==========" | |
| if [ -d "/models" ]; then | |
| model_path="/models/${{ matrix.model_path }}" | |
| else | |
| model_path="${{ matrix.model_path }}" | |
| fi | |
| echo "Model path: $model_path" | |
| ls -la $model_path || true | |
| # Print debug logs | |
| echo "========= Runner debug logs ===============" | |
| ps aux | |
| rocm-smi --showmemuse | |
| rocm-smi --showpids | |
| docker ps -a | |
| echo "========= End runner debug logs ===============" | |
| docker exec "$CONTAINER_NAME" bash -lc " | |
| set -euo pipefail | |
| python3 -m atom.examples.simple_inference \ | |
| --model \"$model_path\" \ | |
| ${{ matrix.extraArgs }} \ | |
| --temperature 0 \ | |
| | grep -E '^Prompt: |^Completion:' | |
| " > atom_test_output.txt | |
| echo "" | |
| echo "========== Showing test output below ==========" | |
| cat atom_test_output.txt | |
| - name: Compare output with golden outputs | |
| if: false | |
| timeout-minutes: 30 | |
| # TODO: skip for all test until it's fixed | |
| run: | | |
| echo "========== Comparing output with golden outputs ==========" | |
| if ! diff -u -B -w --strip-trailing-cr \ | |
| atom_test_output.txt \ | |
| ".github/workflows/golden_outputs/${{ matrix.model_name }}_golden_output.txt"; then | |
| echo "Failed: Output does not match golden outputs." | |
| exit 1 | |
| else | |
| echo "Success: Output matches golden outputs." | |
| fi | |
| - name: Run ATOM accuracy test | |
| timeout-minutes: ${{ matrix.accuracy_timeout_minutes || 30 }} | |
| env: | |
| MODEL_EXTRA_ARGS: ${{ matrix.extraArgs }} | |
| CLIENT_COMMAND: ${{ matrix.client_command || '' }} | |
| ACCURACY_TIMEOUT_MINUTES: ${{ matrix.accuracy_timeout_minutes || 30 }} | |
| run: | | |
| set -euo pipefail | |
| echo "" | |
| echo "========== Launching ATOM server ==========" | |
| if [ -d "/models" ]; then | |
| model_path="/models/${{ matrix.model_path }}" | |
| else | |
| model_path="${{ matrix.model_path }}" | |
| fi | |
| # Pipe via stdin so container bash parses shell quoting in extraArgs | |
| # (e.g. single-quoted JSON in --default-chat-template-kwargs) naturally. | |
| echo ".github/scripts/atom_test.sh launch $model_path $MODEL_EXTRA_ARGS" | \ | |
| docker exec -i "$CONTAINER_NAME" bash -l | |
| echo "" | |
| echo "========== Running accuracy test ==========" | |
| docker exec \ | |
| -e CLIENT_COMMAND="${CLIENT_COMMAND}" \ | |
| -e ACCURACY_TIMEOUT_MINUTES="${ACCURACY_TIMEOUT_MINUTES}" \ | |
| -e GPU_NAME="${{ steps.gpu-info.outputs.gpu_name }}" \ | |
| -e GPU_VRAM_GB="${{ steps.gpu-info.outputs.gpu_vram_gb }}" \ | |
| -e ROCM_VERSION="${{ steps.gpu-info.outputs.rocm_version }}" \ | |
| "$CONTAINER_NAME" bash -lc " | |
| .github/scripts/atom_test.sh accuracy $model_path | |
| " 2>&1 | tee atom_accuracy_output.txt | |
| - name: Dump server log | |
| if: always() | |
| run: | | |
| docker exec "$CONTAINER_NAME" cat /tmp/atom_server.log 2>/dev/null || true | |
| - name: Dump client log | |
| if: always() | |
| run: | | |
| docker exec "$CONTAINER_NAME" cat /tmp/atom_client.log 2>/dev/null || true | |
| - name: Check accuracy test results | |
| if: success() | |
| env: | |
| MODEL_NAME: ${{ matrix.model_name }} | |
| run: | | |
| result_file=$(ls -1t accuracy_test_results/*.json 2>/dev/null | head -n 1) | |
| if [ -z "$result_file" ] || [ ! -f "$result_file" ]; then | |
| echo "ERROR: No results JSON file found in accuracy_test_results/" | |
| exit 2 | |
| else | |
| echo "RESULT_FILE: $result_file" | |
| fi | |
| flexible_extract_value=$(jq '.results.gsm8k["exact_match,flexible-extract"]' "$result_file") | |
| echo "Flexible extract value: $flexible_extract_value" | |
| # Read threshold from models_accuracy.json (via env var to avoid shell injection) | |
| threshold=$(python3 -c " | |
| import json, os | |
| models = json.load(open('.github/benchmark/models_accuracy.json', encoding='utf-8')) | |
| name = os.environ['MODEL_NAME'] | |
| t = next((m.get('accuracy_threshold', 0) for m in models if m['model_name'] == name), 0) | |
| print(t) | |
| ") | |
| echo "Accuracy test threshold: $threshold" | |
| result=$(awk -v val="$flexible_extract_value" -v threshold="$threshold" 'BEGIN {print (val < threshold) ? 1 : 0}') | |
| if [ "$result" -eq 1 ]; then | |
| echo "Accuracy test failed: $flexible_extract_value < $threshold" | |
| exit 1 | |
| else | |
| echo "Accuracy test passed: $flexible_extract_value >= $threshold" | |
| fi | |
| - name: Collect Test Summary | |
| if: success() | |
| env: | |
| MODEL_NAME: ${{ matrix.model_name }} | |
| run: | | |
| # Read threshold and score for summary | |
| threshold=$(python3 -c " | |
| import json, os | |
| models = json.load(open('.github/benchmark/models_accuracy.json', encoding='utf-8')) | |
| name = os.environ['MODEL_NAME'] | |
| print(next((m.get('accuracy_threshold', 0) for m in models if m['model_name'] == name), 0)) | |
| ") | |
| result_file=$(ls -1t accuracy_test_results/*.json 2>/dev/null | head -n 1) | |
| score=$(jq '.results.gsm8k["exact_match,flexible-extract"]' "$result_file" 2>/dev/null || echo "N/A") | |
| echo "Accuracy Test Summary for ${{ matrix.model_name }} (threshold: ${threshold}, score: ${score}):" >> $GITHUB_STEP_SUMMARY | |
| awk '/\|Tasks\|Version\|/,/^$/ { if (NF > 0) print }' atom_accuracy_output.txt >> $GITHUB_STEP_SUMMARY | |
| - name: Upload output | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.model_name }}_atom_test_output.txt | |
| path: atom_test_output.txt | |
| - name: Upload accuracy results | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: accuracy-${{ matrix.model_name }} | |
| path: accuracy_test_results/*.json | |
| if-no-files-found: ignore | |
| - name: Clean Up | |
| if: always() | |
| run: | | |
| # TODO: run a separate container for cleanup of the workspace due to permission issue to remove some pyc files under __pycache__ whose owners are root. | |
| # We should use non-root user to run the test to avoid this issue. | |
| set -x | |
| echo "========== Cleaning up workspace ==========" | |
| if [[ ${{ matrix.runner }} == atom-mi355-8gpu.predownload ]]; then | |
| docker run --rm -v "${GITHUB_WORKSPACE:-$PWD}":/workspace -w /workspace --privileged rocm/pytorch:latest bash -lc "ls -la /workspace/ && find /workspace -mindepth 1 -delete" || true | |
| fi | |
| docker stop "$CONTAINER_NAME" || true | |
| docker rm "$CONTAINER_NAME" || true | |
| # Remove the pre-built image to free disk space on the runner | |
| docker rmi "rocm/atom-dev:pre-build-${{ env.GITHUB_COMMIT_SHA }}" || true | |
| # ---------- Publish Atomesh accuracy data for the mocker benchmark dashboard ---------- | |
| publish-atomesh-accuracy-data: | |
| name: Publish Atomesh accuracy data | |
| needs: [atomesh-test] | |
| if: always() && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule') | |
| # Serialize with every other gh-pages push so the auto-push below does not | |
| # race concurrent deploys (docs / benchmark dashboards) on the gh-pages branch. | |
| concurrency: | |
| group: gh-pages-deploy | |
| cancel-in-progress: false | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| - name: Download accuracy artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: /tmp/accuracy-results | |
| pattern: accuracy-* | |
| - name: List downloaded artifacts | |
| run: | | |
| echo "=== Downloaded accuracy artifacts ===" | |
| find /tmp/accuracy-results -type f -name '*.json' | head -20 || echo "No JSON files found" | |
| - name: Transform accuracy results for mocker dashboard data | |
| run: | | |
| python3 .github/scripts/accuracy_to_dashboard.py \ | |
| /tmp/accuracy-results \ | |
| --output accuracy-benchmark-input.json \ | |
| --models .github/benchmark/models_accuracy.json \ | |
| --backend ATOMesh \ | |
| --run-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| echo "=== Generated entries ===" | |
| cat accuracy-benchmark-input.json | |
| - name: Prepare existing dashboard data | |
| if: hashFiles('accuracy-benchmark-input.json') != '' | |
| id: prepare_dashboard_data | |
| uses: ./.github/actions/prepare-dashboard-data | |
| with: | |
| data-path: atomesh-accuracy-dashboard/data.js | |
| - name: Store Atomesh accuracy data | |
| if: hashFiles('accuracy-benchmark-input.json') != '' | |
| uses: benchmark-action/github-action-benchmark@v1 | |
| with: | |
| tool: customBiggerIsBetter | |
| output-file-path: accuracy-benchmark-input.json | |
| gh-pages-branch: gh-pages | |
| benchmark-data-dir-path: atomesh-accuracy-dashboard | |
| auto-push: false | |
| max-items-in-chart: 300 | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Validate dashboard data after write | |
| if: hashFiles('accuracy-benchmark-input.json') != '' | |
| uses: ./.github/actions/validate-dashboard-data | |
| with: | |
| data-path: atomesh-accuracy-dashboard/data.js | |
| min-entries: ${{ steps.prepare_dashboard_data.outputs.entry_count }} | |
| - name: Push dashboard data | |
| if: hashFiles('accuracy-benchmark-input.json') != '' | |
| run: git push origin gh-pages |