Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 90 additions & 13 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ on:
duration:
description: Benchmark duration per preset (seconds)
required: false
default: "5"
default: "60"
capture_gpu_culling:
description: Capture the bounded gpu-culling-scale extreme/traversal CPU-vs-GPU source pair
required: false
type: boolean
default: false

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -35,7 +40,8 @@ jobs:
issues: write
statuses: write
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 30
# Long scheduled/manual acceptance captures remain externally bounded.
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -63,7 +69,7 @@ jobs:
});
const shouldRun = files.some((file) => {
const name = file.filename;
return name === 'build.zig' || name.startsWith('src/') || name.startsWith('modules/') || name.startsWith('assets/shaders/');
return name === 'build.zig' || name.startsWith('src/') || name.startsWith('modules/') || name.startsWith('assets/shaders/') || name.startsWith('scripts/') || name.startsWith('docs/benchmarks/') || name === '.github/workflows/benchmark.yml';
});
core.setOutput('run', shouldRun ? 'true' : 'false');

Expand Down Expand Up @@ -96,28 +102,96 @@ jobs:
uses: ./.github/actions/run-with-log
with:
name: Benchmark
timeout: 20m
timeout: ${{ github.event_name == 'schedule' && '55m' || github.event_name == 'workflow_dispatch' && '55m' || '20m' }}
log-file: benchmark.log
command: mkdir -p "$MESA_SHADER_CACHE_DIR" && nix develop .#ci-graphics --command bash scripts/run_benchmark.sh --duration "$BENCHMARK_DURATION" --presets low,medium,high --output-dir benchmark-results --per-preset-timeout 600
command: mkdir -p "$MESA_SHADER_CACHE_DIR" && nix develop .#ci-graphics --command bash scripts/run_benchmark.sh --duration "$BENCHMARK_DURATION" --presets low,medium,high --scenarios stationary,traversal,rapid-turn,teleport-eviction --compact-modes off,auto --benchmark-world overworld --output-dir benchmark-results --per-preset-timeout 600
env:
XDG_RUNTIME_DIR: /tmp/runtime-runner
WAYLAND_DISPLAY: headless
MESA_SHADER_CACHE_DIR: /tmp/mesa_shader_cache
SDL_AUDIODRIVER: dummy
ZIGCRAFT_SAFE_MODE: "1"
BENCHMARK_DURATION: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.duration || '5' }}
# PR/push runs are bounded canaries. Scheduled and manually requested
# captures are longer acceptance evidence, not synthetic fixtures.
BENCHMARK_DURATION: ${{ github.event_name == 'schedule' && '60' || github.event_name == 'workflow_dispatch' && github.event.inputs.duration || '5' }}
ZIGCRAFT_BENCHMARK_GPU_ADAPTER: Lavapipe (Mesa software Vulkan)
ZIGCRAFT_BENCHMARK_GPU_DRIVER: Mesa Lavapipe supplied by the pinned Nix environment
ZIGCRAFT_BENCHMARK_RUNNER: blacksmith-2vcpu-ubuntu-2404 GitHub Actions runner
ZIGCRAFT_BENCHMARK_ZIG_TOOLCHAIN: Zig 0.16.0 supplied by the pinned Nix flake

- name: Run Phase 5 long-session streaming stress gate
if: steps.gate.outputs.run == 'true'
uses: ./.github/actions/run-with-log
with:
name: Phase 5 Streaming Stress
timeout: 15m
log-file: phase5-streaming-stress.log
command: nix develop .#ci-unit --command zig build phase5-stress-gate -Dphase5-stress-iterations="$PHASE5_STRESS_ITERATIONS"
env:
# The scheduled run is longer by operation count, never by a flaky
# elapsed-time threshold. PR feedback stays bounded.
PHASE5_STRESS_ITERATIONS: ${{ github.event_name == 'schedule' && '768' || '64' }}

- name: Validate compact benchmark evidence matrix
if: steps.gate.outputs.run == 'true'
run: python3 scripts/benchmark_baseline.py validate-compact-matrix benchmark-results

- name: Capture dedicated CPU-vs-GPU culling sources
# Scheduled captures always retain a fresh pair. Manual runs opt in so
# ordinary canaries stay fast; each source is independently bounded.
if: steps.gate.outputs.run == 'true' && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.capture_gpu_culling == 'true'))
uses: ./.github/actions/run-with-log
with:
name: GPU Culling Baseline Sources
timeout: 32m
log-file: gpu-culling-benchmark.log
command: mkdir -p "$MESA_SHADER_CACHE_DIR" && nix develop .#ci-graphics --command bash -c 'scripts/run_benchmark.sh --duration 60 --presets extreme --scenarios traversal --compact-modes auto --gpu-culling off --gpu-culling-threshold 128 --benchmark-fixture gpu-culling-scale --benchmark-horizon-distance 4096 --benchmark-lod-memory-budget-mb 2048 --benchmark-require-gpu-candidates 1024 --benchmark-world flat --output-dir gpu-culling-results/cpu --per-preset-timeout 900 && scripts/run_benchmark.sh --duration 60 --presets extreme --scenarios traversal --compact-modes auto --gpu-culling on --gpu-culling-threshold 128 --benchmark-fixture gpu-culling-scale --benchmark-horizon-distance 4096 --benchmark-lod-memory-budget-mb 2048 --benchmark-require-gpu-candidates 1024 --benchmark-world flat --output-dir gpu-culling-results/gpu --per-preset-timeout 900'
env:
XDG_RUNTIME_DIR: /tmp/runtime-runner
WAYLAND_DISPLAY: headless
MESA_SHADER_CACHE_DIR: /tmp/mesa_shader_cache
SDL_AUDIODRIVER: dummy
ZIGCRAFT_SAFE_MODE: "1"
ZIGCRAFT_BENCHMARK_GPU_ADAPTER: Lavapipe (Mesa software Vulkan)
ZIGCRAFT_BENCHMARK_GPU_DRIVER: Mesa Lavapipe supplied by the pinned Nix environment
ZIGCRAFT_BENCHMARK_RUNNER: blacksmith-2vcpu-ubuntu-2404 GitHub Actions runner
ZIGCRAFT_BENCHMARK_ZIG_TOOLCHAIN: Zig 0.16.0 supplied by the pinned Nix flake

- name: Validate fresh CPU-vs-GPU culling pair
if: steps.gate.outputs.run == 'true' && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.capture_gpu_culling == 'true'))
run: |
python3 scripts/benchmark_baseline.py assemble-gpu-culling --overwrite \
--output gpu-culling-results/gpu-culling-baseline.json \
gpu-culling-results/cpu/auto/extreme/traversal.json \
gpu-culling-results/gpu/auto/extreme/traversal.json
python3 scripts/benchmark_baseline.py validate-gpu-culling \
gpu-culling-results/gpu-culling-baseline.json

- name: Stop headless Wayland compositor
if: always() && steps.gate.outputs.run == 'true'
uses: ./.github/actions/stop-weston

- name: Compare against baseline
- name: Reject Vulkan validation errors in benchmark log
if: steps.gate.outputs.run == 'true'
run: |
if rg -n -i 'vuid-|validation.*(error|failed)|(error|failed).*validation' benchmark.log; then
printf 'Vulkan validation errors were reported during the benchmark.\n' >&2
exit 1
fi

- name: Compare against baseline
# A 5-second canary must not be numerically compared with a 60-second
# acceptance capture. The compatibility command also enforces this.
if: steps.gate.outputs.run == 'true' && github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'
id: compare
run: |
for preset in low medium high; do
bash scripts/compare_benchmarks.sh docs/benchmarks/baseline.json "benchmark-results/${preset}.json" --preset "$preset"
done
if ! python3 scripts/benchmark_baseline.py compatibility docs/benchmarks/baseline.json benchmark-results/auto/low/stationary.json --preset low --scenario stationary; then
printf 'Skipping numeric baseline comparison: checked reference hardware/provenance differs from this CI runner. Matrix, SLO, validation, and Bencher gates still apply.\n'
exit 0
fi
for preset in low medium high; do for scenario in stationary traversal rapid-turn teleport-eviction; do
bash scripts/compare_benchmarks.sh docs/benchmarks/baseline.json "benchmark-results/auto/${preset}/${scenario}.json" --preset "$preset" --scenario "$scenario"
done; done

- name: Install Bencher CLI
if: steps.gate.outputs.run == 'true' && env.BENCHER_API_TOKEN != '' && env.BENCHER_PROJECT != ''
Expand All @@ -128,16 +202,16 @@ jobs:
env:
BENCHER_BRANCH: ${{ github.head_ref || github.ref_name }}
run: |
for preset in low medium high; do
for preset in low medium high; do for scenario in stationary traversal rapid-turn teleport-eviction; do
bencher run \
--project "$BENCHER_PROJECT" \
--branch "$BENCHER_BRANCH" \
--testbed "github-actions-lavapipe" \
--token "$BENCHER_API_TOKEN" \
--adapter json \
--err \
"cat benchmark-results/${preset}.json"
done
"cat benchmark-results/auto/${preset}/${scenario}.json"
done; done

- name: Comment Bencher dashboard
if: steps.gate.outputs.run == 'true' && github.event_name == 'pull_request' && env.BENCHER_DASHBOARD_URL != ''
Expand All @@ -158,7 +232,10 @@ jobs:
name: benchmark-results
path: |
benchmark-results
gpu-culling-results
benchmark.log
gpu-culling-benchmark.log
phase5-streaming-stress.log
weston.log
retention-days: 30

Expand Down
46 changes: 42 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
- "libs/**"
- "assets/shaders/**"
- "scripts/**"
- "docs/benchmarks/**"
- "build.zig"
- "build.zig.zon"
- "flake.nix"
Expand All @@ -18,6 +19,7 @@ on:
- ".github/actions/setup-lavapipe/**"
- ".github/vulkan/**"
- ".github/workflows/build.yml"
- ".github/workflows/benchmark.yml"
pull_request:
branches: [dev]
paths:
Expand All @@ -26,6 +28,7 @@ on:
- "libs/**"
- "assets/shaders/**"
- "scripts/**"
- "docs/benchmarks/**"
- "build.zig"
- "build.zig.zon"
- "flake.nix"
Expand All @@ -35,6 +38,7 @@ on:
- ".github/actions/setup-lavapipe/**"
- ".github/vulkan/**"
- ".github/workflows/build.yml"
- ".github/workflows/benchmark.yml"
workflow_dispatch:
inputs:
ref:
Expand Down Expand Up @@ -81,6 +85,7 @@ jobs:
- 'libs/**'
- 'assets/shaders/**'
- 'scripts/**'
- 'docs/benchmarks/**'
- 'build.zig'
- 'build.zig.zon'
- 'flake.nix'
Expand All @@ -90,6 +95,7 @@ jobs:
- '.github/actions/setup-lavapipe/**'
- '.github/vulkan/**'
- '.github/workflows/build.yml'
- '.github/workflows/benchmark.yml'
platform_changes:
- 'src/**'
- 'modules/**'
Expand Down Expand Up @@ -191,6 +197,14 @@ jobs:
log-file: unit-test-${{ matrix.optimize }}.log
command: nix develop .#ci-unit --command zig build -Doptimize=${{ matrix.optimize }} test

- name: Run Phase 5 compact LOD gate
if: needs.changes.outputs.code_changes == 'true' && matrix.optimize == 'Debug'
run: nix develop .#ci-unit --command zig build phase5-gate

- name: Run bounded Phase 5 streaming stress gate
if: needs.changes.outputs.code_changes == 'true' && matrix.optimize == 'Debug'
run: nix develop .#ci-unit --command zig build phase5-stress-gate -Dphase5-stress-iterations=64

- name: Upload unit test log
if: failure()
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -221,7 +235,7 @@ jobs:
contents: read
id-token: write
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 45
timeout-minutes: 75
needs: [changes, unit-test]
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -274,15 +288,38 @@ jobs:
ZIGCRAFT_SMOKE_FRAMES: "3"
ZIGCRAFT_SAFE_MODE: "1"

- name: Run Phase 5 production visual-motion and saved-world gate
if: needs.changes.outputs.code_changes == 'true'
uses: ./.github/actions/run-with-log
with:
name: Phase 5 Visual Motion and Saved-World Reload Gate
timeout: 35m
log-file: phase5-visual-gate.log
command: nix develop .#ci-graphics --command zig build phase5-visual-gate
env:
XDG_RUNTIME_DIR: /tmp/runtime-runner
WAYLAND_DISPLAY: headless

- name: Upload Phase 5 visual evidence
if: always() && needs.changes.outputs.code_changes == 'true'
uses: actions/upload-artifact@v7
with:
name: phase5-visual-evidence
path: |
zig-out/phase5-visual-smoke/
phase5-visual-gate.log
if-no-files-found: ignore
retention-days: 14

- name: Fail on Vulkan validation log errors
if: needs.changes.outputs.code_changes == 'true'
run: |
set -euo pipefail
if grep -E "Vulkan validation error|Validation Error:|VUID-" integration-test.log world-smoke-test.log; then
echo "Vulkan validation errors were found in integration logs." >&2
if rg -n -e 'Vulkan validation error|Validation Error:|VUID-' integration-test.log world-smoke-test.log phase5-visual-gate.log; then
echo "Vulkan validation errors were found in integration or Phase 5 visual logs." >&2
exit 1
fi
echo "No Vulkan validation errors found in integration logs."
echo "No Vulkan validation errors found in integration or Phase 5 visual logs."

- name: Stop headless Wayland compositor
if: always() && needs.changes.outputs.code_changes == 'true'
Expand All @@ -296,6 +333,7 @@ jobs:
path: |
integration-test.log
world-smoke-test.log
phase5-visual-gate.log
weston.log
if-no-files-found: ignore
retention-days: 7
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/opencode-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ jobs:
ZHIPU_API_KEY: ${{ secrets.ZHIPU_API_KEY }}
with:
model: zhipuai-coding-plan/glm-5.2
variant: max
use_github_token: true
prompt: ${{ env.PROMPT }}

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ blocks-temp/
libs/zig-image/
result
node_modules/
__pycache__/
.direnv/
*-profile*
test_output.txt
Expand Down
Loading
Loading