name: Comparative benchmark

on:
  workflow_dispatch:
    inputs:
      duration:
        description: Measured seconds per target and repetition
        required: true
        default: 120
        type: number
      warmup:
        description: Untimed warmup seconds per target and repetition
        required: true
        default: 15
        type: number
      repetitions:
        description: Measured repetitions
        required: true
        default: 3
        type: number
      pipeline:
        description: GET pipeline depth
        required: true
        default: "32"
        type: choice
        options: ["32", "1"]
      workers:
        description: pg_local_cache worker processes
        required: true
        default: "4"
        type: choice
        options: ["4", "1"]
      keys:
        description: Warm keyspace size
        required: true
        default: "16384"
        type: choice
        options: ["16384", "1024"]
  schedule:
    - cron: "17 3 1 * *"

permissions:
  contents: read

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

jobs:
  compare:
    name: pg_local_cache vs Valkey vs Redis vs PostgreSQL
    runs-on: ubuntu-24.04
    timeout-minutes: 90
    steps:
      - name: Check out source
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Validate whole-row benchmark source
        run: |
          bash -n benchmarks/run.sh
          python3 -m py_compile \
            benchmarks/compare.py \
            benchmarks/scenarios.py \
            benchmarks/whole_row.py \
            tests/whole_row_benchmark_test.py
          python3 -m unittest -v \
            tests/whole_row_benchmark_test.py

      - name: Run whole-row RESP and PostgreSQL comparisons
        env:
          PGLC_BENCH_DURATION: ${{ inputs.duration || '120' }}
          PGLC_BENCH_WARMUP_SECONDS: ${{ inputs.warmup || '15' }}
          PGLC_BENCH_REPETITIONS: ${{ inputs.repetitions || '3' }}
          PGLC_BENCH_PIPELINE: ${{ inputs.pipeline || '32' }}
          PGLC_BENCH_PG_LOCAL_CACHE_WORKERS: ${{ inputs.workers || '4' }}
          PGLC_BENCH_KEYS: ${{ inputs.keys || '16384' }}
          PGLC_BENCH_SINGLEFLIGHT_WAIT_MS: "250"
          PGLC_BENCH_ROW_RESP_MIN_OPS: "10000"
          PGLC_BENCH_ROW_SQL_MIN_OPS: "10000"
          PGLC_BENCH_SERVER_CPUS: "2"
          PGLC_BENCH_CLIENT_CPUS: "2"
          PGLC_BENCH_OUTPUT_DIR: ${{ github.workspace }}/benchmark-results
        run: bash benchmarks/run.sh

      - name: Add report to job summary
        if: always()
        run: |
          if [[ -f benchmark-results/whole-row.md ]]; then
            cat benchmark-results/whole-row.md >> "$GITHUB_STEP_SUMMARY"
          elif [[ -f benchmark-results/whole-row-failure.md ]]; then
            cat benchmark-results/whole-row-failure.md >> "$GITHUB_STEP_SUMMARY"
          fi

      - name: Upload machine-readable and Markdown reports
        if: always()
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: pg_local_cache-comparison
          path: benchmark-results/
          if-no-files-found: warn
          retention-days: 30

  sql-only:
    name: SQL-only GET/MGET API (prepared + unnamed extended)
    runs-on: ubuntu-24.04
    timeout-minutes: 70
    steps:
      - name: Check out source
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Validate SQL-only benchmark source
        run: |
          python3 -m py_compile benchmarks/sql_only.py tests/sql_only_benchmark_test.py
          python3 -m unittest -v tests/sql_only_benchmark_test.py
          bash -n tests/docker_sql_only_smoke.sh

      - name: Benchmark the tokenless SQL-only deployment
        env:
          PGLC_SQL_ONLY_BENCH_DURATION: ${{ inputs.duration || '120' }}
          PGLC_SQL_ONLY_BENCH_WARMUP_SECONDS: ${{ inputs.warmup || '15' }}
          PGLC_SQL_ONLY_BENCH_REPETITIONS: ${{ inputs.repetitions || '3' }}
          PGLC_SQL_ONLY_BENCH_CONCURRENCY: "16"
          PGLC_SQL_ONLY_BENCH_PIPELINE: "32"
          PGLC_SQL_ONLY_BENCH_KEYS: "4096"
          PGLC_SQL_ONLY_BENCH_PAYLOAD_BYTES: "3000"
          PGLC_SQL_ONLY_BENCH_PREPARED_MIN_OPS: "10000"
          PGLC_SQL_ONLY_BENCH_EXTENDED_MIN_OPS: "10000"
          PGLC_SQL_ONLY_BENCH_LATENCY_MIN_SAMPLES: "5000"
          PGLC_SQL_ONLY_BENCH_MIN_CACHED_TO_DIRECT_RATIO: "1.50"
          PGLC_SQL_ONLY_BENCH_MIN_CACHED_TO_STOCK_RATIO: "1.50"
          PGLC_SQL_ONLY_BENCH_SCALING_SNAPSHOT: "true"
          PGLC_SQL_ONLY_BENCH_SCALING_DURATION: "3"
          PGLC_SQL_ONLY_BENCH_SCALING_WARMUP_SECONDS: "1"
          PGLC_SQL_ONLY_BENCH_SCALING_LATENCY_DURATION: "3"
          PGLC_SQL_ONLY_BENCH_SCALING_LATENCY_SAMPLE_RATE: "0.10"
          PGLC_SQL_ONLY_BENCH_SCALING_LATENCY_MIN_SAMPLES: "500"
          PGLC_SQL_ONLY_BENCH_SCALING_REPETITIONS: "1"
          PGLC_SQL_ONLY_BENCH_CLIENT_MEMORY: "1g"
          PGLC_SQL_ONLY_BENCH_OUTPUT_DIR: ${{ github.workspace }}/sql-only-results
        run: bash tests/docker_sql_only_smoke.sh

      - name: Add SQL-only report to job summary
        if: always()
        run: |
          if [[ -f sql-only-results/sql-only.md ]]; then
            cat sql-only-results/sql-only.md >> "$GITHUB_STEP_SUMMARY"
          elif [[ -f sql-only-results/sql-only-failure.md ]]; then
            cat sql-only-results/sql-only-failure.md >> "$GITHUB_STEP_SUMMARY"
          fi

      - name: Upload SQL-only machine-readable and Markdown reports
        if: always()
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: pg_local_cache-sql-only
          path: sql-only-results/
          if-no-files-found: warn
          retention-days: 90
