name: PR Benchmark (SMG Components)

on:
  push:
    branches: [ main ]
    paths:
      - "sgl-model-gateway/**"
  pull_request:
    branches: [ main ]
    paths:
      - "sgl-model-gateway/**"
  workflow_dispatch:

concurrency:
  group: pr-benchmark-rust-${{ github.ref }}
  cancel-in-progress: true

env:
  RUSTC_WRAPPER: sccache
  SCCACHE_GHA_ENABLED: "true"

permissions:
  contents: read
  pull-requests: write
  issues: write

jobs:
  benchmark-compile-check:
    name: Benchmark Compilation Check
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          bash scripts/ci/cuda/ci_install_gateway_dependencies.sh

      - name: Configure sccache
        uses: mozilla-actions/sccache-action@v0.0.9
        with:
          version: "v0.12.0"
          disable_annotations: true

      - name: Rust cache
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: sgl-model-gateway
          shared-key: "rust-cache"
          save-if: true
          cache-all-crates: true
          cache-on-failure: true

      - name: Check benchmarks compile
        run: |
          source "$HOME/.cargo/env"
          cd sgl-model-gateway/
          cargo check --benches

      - name: Show sccache stats
        if: always()
        run: sccache --show-stats

  benchmark:
    name: Benchmark - ${{ matrix.name }}
    if: |
      github.repository == 'sgl-project/sglang' &&
      (github.event_name == 'push' ||
       github.event_name == 'workflow_dispatch' ||
       (contains(github.event.pull_request.labels.*.name, 'router-benchmark') &&
        contains(github.event.pull_request.labels.*.name, 'run-ci')))
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Request Processing
            bench_name: request_processing
            bench_args: "benchmark_summary --exact"
            runner: ubuntu-latest
            sccache_version: "v0.12.0"
            artifact_name: request-processing-results
            artifact_path: criterion/benchmark_summary/
          - name: Manual Policy
            bench_name: manual_policy_benchmark
            bench_args: ""
            runner: ubuntu-latest
            sccache_version: "v0.12.0"
            artifact_name: manual-policy-results
            artifact_path: criterion/manual_policy*/
    runs-on: ${{ matrix.runner }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 100

      - name: Install dependencies
        run: |
          bash scripts/ci/cuda/ci_install_gateway_dependencies.sh

      - name: Configure sccache
        uses: mozilla-actions/sccache-action@v0.0.9
        with:
          version: ${{ matrix.sccache_version }}
          disable_annotations: true

      - name: Rust cache
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: sgl-model-gateway
          shared-key: "rust-cache"
          cache-all-crates: true
          cache-on-failure: true
          save-if: true

      - name: Run benchmark
        timeout-minutes: 30
        run: |
          source "$HOME/.cargo/env"
          cd sgl-model-gateway/
          if command -v sccache &> /dev/null; then
            echo "Testing sccache availability..."
            export RUSTC_WRAPPER=sccache
            export SCCACHE_GHA_ENABLED="true"
            if sccache --start-server 2>/dev/null && sccache --show-stats 2>/dev/null; then
              echo "sccache is working, using it for compilation"
            else
              echo "sccache failed to start, falling back to regular cargo"
              unset RUSTC_WRAPPER
              unset SCCACHE_GHA_ENABLED
            fi
          else
            echo "sccache not available, using regular cargo"
          fi
          cargo bench --bench ${{ matrix.bench_name }} -- ${{ matrix.bench_args }} 2>&1 | tee benchmark_output.txt

      - name: Upload benchmark results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact_name }}-${{ github.sha }}
          path: |
            sgl-model-gateway/target/${{ matrix.artifact_path }}
            sgl-model-gateway/benchmark_output.txt
          retention-days: 30

      - name: Show sccache stats
        if: always()
        run: sccache --show-stats

  benchmark-summary:
    name: Benchmark Summary
    needs: [benchmark]
    if: always() && (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request')
    runs-on: ubuntu-latest
    steps:
      - name: Download all benchmark results
        uses: actions/download-artifact@v4
        with:
          pattern: '*-results-${{ github.sha }}'
          path: benchmark-results

      - name: Generate summary
        run: |
          generate_section() {
            local title="$1" dir_name="$2" lines="${3:-100}"
            local dir="benchmark-results/${dir_name}-${{ github.sha }}"
            echo "### $title" >> summary.md
            if [ -d "$dir" ]; then
              echo "✅ **Completed**" >> summary.md
              if [ -f "$dir/benchmark_output.txt" ]; then
                echo -e "\n<details>\n<summary>View Results</summary>\n\n\`\`\`" >> summary.md
                tail -"$lines" "$dir/benchmark_output.txt" >> summary.md
                echo -e "\`\`\`\n</details>" >> summary.md
              fi
            else
              echo "❌ Failed or skipped" >> summary.md
            fi
            echo "" >> summary.md
          }

          echo "## 🚀 Benchmark Results Summary" > summary.md
          echo "" >> summary.md

          generate_section "Request Processing" "request-processing-results" 60
          generate_section "Manual Policy (Sticky Sessions)" "manual-policy-results" 100

          echo -e "---\n_Generated at $(date -u '+%Y-%m-%d %H:%M:%S UTC')_" >> summary.md

          cat summary.md
          cat summary.md >> $GITHUB_STEP_SUMMARY

      - name: Upload summary
        uses: actions/upload-artifact@v4
        with:
          name: benchmark-summary-${{ github.sha }}
          path: summary.md
          retention-days: 30
