name: Profiling (Flamegraphs)

on:
  workflow_dispatch:

env:
  ITERATIONS: "1"
  ENABLE_PROFILING: "true"
  PROFILING_FIXTURES: "pdf_small,pdf_medium,docx_simple,html_simple,image_table,markdown_technical"
  ORT_VERSION: "1.24.2"
  CARGO_TERM_COLOR: always
  CARGO_INCREMENTAL: 0
  RUSTFLAGS: "-g"
  MACOSX_DEPLOYMENT_TARGET: "14.0"
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
  RUST_BACKTRACE: short
  RUST_MIN_STACK: 16777216

permissions:
  contents: read

defaults:
  run:
    shell: bash

concurrency:
  group: profiling-${{ github.ref }}
  cancel-in-progress: true

jobs:
  setup:
    name: Build harness + native libs (with profiling)
    runs-on: ubuntu-latest
    timeout-minutes: 120
    permissions:
      contents: read
    outputs:
      artifact-name: profiling-target
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Ensure benchmark harness exists
        run: scripts/benchmarks/ensure-benchmark-harness-exists.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build workspace (native libs + harness with profiling)
        env:
          ENABLE_PROFILING: "true"
        run: task rust:build:profiling

      - name: Log disk space before artifact upload
        run: scripts/ci/validate/show-disk-space.sh "Disk space before artifact upload"

      - name: Upload target artifact
        uses: actions/upload-artifact@v7
        with:
          name: profiling-target
          path: |
            target/release
          retention-days: 7

      - name: Log disk space after artifact upload
        run: scripts/ci/validate/show-disk-space.sh "Disk space after artifact upload"

  bench-native:
    name: kreuzberg-rust (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-rust
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-rust-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-rust-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-python-sync:
    name: kreuzberg-python (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Python
        uses: kreuzberg-dev/actions/setup-python-env@v1
        with:
          python-version: "3.11"
          cache-prefix: profiling-python

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Python bindings
        run: task python:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-python
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-python-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-python-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-python-async:
    name: kreuzberg-python-async-OLD (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Python
        uses: kreuzberg-dev/actions/setup-python-env@v1
        with:
          python-version: "3.11"
          cache-prefix: profiling-python

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Python bindings
        run: task python:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-python-async-OLD
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-python-async-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-python-async-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-python-batch:
    name: kreuzberg-python-batch (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Python
        uses: kreuzberg-dev/actions/setup-python-env@v1
        with:
          python-version: "3.11"
          cache-prefix: profiling-python

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Python bindings
        run: task python:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-python-batch
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-python-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-python-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-node-async:
    name: kreuzberg-node (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Node
        uses: kreuzberg-dev/actions/setup-node-workspace@v1

      - name: Verify Node setup (async)
        run: scripts/ci/benchmarks/verify-node-setup.sh "Node setup (async)"

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Node bindings and install locally
        env:
          TARGET: x86_64-unknown-linux-gnu
        run: task node:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-node
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-node-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-node-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-node-batch:
    name: kreuzberg-node-batch (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Node
        uses: kreuzberg-dev/actions/setup-node-workspace@v1

      - name: Verify Node setup (batch)
        run: scripts/ci/benchmarks/verify-node-setup.sh "Node setup (batch)"

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Node bindings and install locally
        env:
          TARGET: x86_64-unknown-linux-gnu
        run: task node:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-node-batch
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-node-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-node-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-wasm-async:
    name: kreuzberg-wasm-async (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Node
        uses: kreuzberg-dev/actions/setup-node-workspace@v1

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build WASM bindings
        run: task wasm:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-wasm-async
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-wasm-async-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-wasm-async-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-wasm-batch:
    name: kreuzberg-wasm-batch (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Node
        uses: kreuzberg-dev/actions/setup-node-workspace@v1

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build WASM bindings
        run: task wasm:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-wasm-batch
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-wasm-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-wasm-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-ruby-sync:
    name: kreuzberg-ruby (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.2"

      - name: Install Bundler
        shell: bash
        run: scripts/ci/ruby/install-bundler.sh

      - name: Install Ruby deps
        shell: bash
        run: scripts/ci/ruby/install-ruby-deps.sh

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Vendor kreuzberg core for Ruby
        run: python3 scripts/ci/ruby/vendor-kreuzberg-core.py

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Ruby native gem
        env:
          PLATFORM: x86_64-linux
        run: task ruby:build:bindings

      - name: Compile Ruby native extension
        shell: bash
        run: scripts/ci/ruby/compile-extension.sh

      - name: Build kreuzberg CLI
        shell: bash
        run: task rust:cli:build

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-ruby
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-ruby-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-ruby-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-ruby-batch:
    name: kreuzberg-ruby-batch (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.2"

      - name: Install Bundler
        shell: bash
        run: scripts/ci/ruby/install-bundler.sh

      - name: Install Ruby deps
        shell: bash
        run: scripts/ci/ruby/install-ruby-deps.sh

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Vendor kreuzberg core for Ruby
        run: python3 scripts/ci/ruby/vendor-kreuzberg-core.py

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Ruby native gem
        env:
          PLATFORM: x86_64-linux
        run: task ruby:build:bindings

      - name: Compile Ruby native extension
        shell: bash
        run: scripts/ci/ruby/compile-extension.sh

      - name: Build kreuzberg CLI
        shell: bash
        run: task rust:cli:build

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-ruby-batch
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-ruby-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-ruby-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-go-sync:
    name: kreuzberg-go-sync (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: "1.26.x"
          cache-dependency-path: packages/go/v5/go.sum

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Prime Go modules
        working-directory: packages/go/v5
        run: go mod download

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Go bindings
        run: task go:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-go-sync
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
          KREUZBERG_BENCHMARK_DEBUG: "true"
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-go-sync-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-go-sync-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-go-batch:
    name: kreuzberg-go-batch (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: "1.26.x"
          cache-dependency-path: packages/go/v5/go.sum

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Prime Go modules
        working-directory: packages/go/v5
        run: go mod download

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Go bindings
        run: task go:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-go-batch
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
          KREUZBERG_BENCHMARK_DEBUG: "true"
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-go-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-go-batch-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-java-sync:
    name: kreuzberg-java-sync (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup Java
        uses: actions/setup-java@v5
        id: setup-java
        with:
          distribution: "temurin"
          java-version: "25"

      - name: Setup Maven 3.9.11
        uses: kreuzberg-dev/actions/setup-maven@v1

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build Java bindings
        run: task java:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-java-sync
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-java-sync-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-java-sync-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7

  bench-csharp-sync:
    name: kreuzberg-csharp-sync (${{ matrix.mode }}) [profiling]
    needs: setup
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        mode: [single-file, batch]
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Free disk space
        uses: kreuzberg-dev/actions/free-disk-space-linux@v1

      - name: Download build artifacts
        uses: actions/download-artifact@v8
        with:
          name: ${{ needs.setup.outputs.artifact-name }}
          path: target/release

      - name: Restore benchmark binary permissions
        run: scripts/benchmarks/restore-binary-permissions.sh

      - name: Install system dependencies
        uses: ./.github/actions/install-system-deps

      - name: Setup OpenSSL
        uses: kreuzberg-dev/actions/setup-openssl@v1

      - name: Setup Rust toolchain
        uses: kreuzberg-dev/actions/setup-rust@v1
        with:
          cache-key-prefix: profiling
          use-sccache: true

      - name: Setup .NET
        uses: actions/setup-dotnet@v5
        with:
          dotnet-version: "10.0.x"

      - name: Setup ONNX Runtime
        uses: ./.github/actions/setup-onnx-runtime
        with:
          ort-version: ${{ env.ORT_VERSION }}

      - name: Setup Layout Models
        uses: ./.github/actions/setup-layout-models

      - name: Install Task
        uses: kreuzberg-dev/actions/install-task@v1

      - name: Build C# bindings
        run: task csharp:build:bindings

      - name: Run benchmark
        env:
          FRAMEWORK: kreuzberg-csharp-sync
          MODE: ${{ matrix.mode }}
          ITERATIONS: ${{ env.ITERATIONS }}
          ENABLE_PROFILING: ${{ env.ENABLE_PROFILING }}
          PROFILING_FIXTURES: ${{ env.PROFILING_FIXTURES }}
        run: task benchmark:run

      - name: Upload benchmark artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: profiling-results-kreuzberg-csharp-sync-${{ matrix.mode }}-${{ github.run_id }}
          path: benchmark-results/
          retention-days: 7

      - name: Upload flamegraph artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: flamegraphs-kreuzberg-csharp-sync-${{ matrix.mode }}-${{ github.run_id }}
          path: flamegraphs/
          retention-days: 7
