Add native Rust-based MySQL parser extension #70
Workflow file for this run
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: Native AST Walk Perf | |
| on: | |
| push: | |
| paths: | |
| - '.github/workflows/native-ast-perf.yml' | |
| - 'packages/mysql-on-sqlite/src/mysql/native/**' | |
| - 'packages/mysql-on-sqlite/tests/tools/run-native-ast-walk-benchmark.php' | |
| - 'packages/php-ext-wp-mysql-parser/**' | |
| pull_request: | |
| paths: | |
| - '.github/workflows/native-ast-perf.yml' | |
| - 'packages/mysql-on-sqlite/src/mysql/native/**' | |
| - 'packages/mysql-on-sqlite/tests/tools/run-native-ast-walk-benchmark.php' | |
| - 'packages/php-ext-wp-mysql-parser/**' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| perf: | |
| name: Native AST walk benchmark | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.2' | |
| coverage: none | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install native build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libclang-dev | |
| echo "PHP_CONFIG=$(command -v php-config)" >> "$GITHUB_ENV" | |
| LIBCLANG_SO="$(find /usr/lib -name 'libclang.so*' | head -n 1)" | |
| echo "LIBCLANG_PATH=$(dirname "$LIBCLANG_SO")" >> "$GITHUB_ENV" | |
| - name: Install Composer dependencies (root) | |
| uses: ramsey/composer-install@v3 | |
| with: | |
| ignore-cache: "yes" | |
| composer-options: "--optimize-autoloader" | |
| - name: Install Composer dependencies (mysql-on-sqlite) | |
| uses: ramsey/composer-install@v3 | |
| with: | |
| working-directory: packages/mysql-on-sqlite | |
| ignore-cache: "yes" | |
| composer-options: "--optimize-autoloader" | |
| - name: Download MySQL test query corpus | |
| working-directory: packages/mysql-on-sqlite | |
| run: bash tests/tools/mysql-download-tests.sh || true | |
| - name: Build parser extension (release) | |
| run: cargo build --release | |
| working-directory: packages/php-ext-wp-mysql-parser | |
| - name: Locate built extension | |
| run: | | |
| EXT="$GITHUB_WORKSPACE/packages/php-ext-wp-mysql-parser/target/release/libwp_mysql_parser.so" | |
| test -f "$EXT" || { echo "Extension not built at $EXT"; exit 1; } | |
| echo "NATIVE_EXT=$EXT" >> "$GITHUB_ENV" | |
| - name: Benchmark — pure-PHP path (parse only) | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| php tests/tools/run-native-ast-walk-benchmark.php --no-walk | tee php-parse-only.txt | |
| - name: Benchmark — pure-PHP path (walk) | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| php tests/tools/run-native-ast-walk-benchmark.php | tee php-walk.txt | |
| - name: Benchmark — native path (parse only) | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| php -d extension="$NATIVE_EXT" tests/tools/run-native-ast-walk-benchmark.php --no-walk | tee native-parse-only.txt | |
| - name: Benchmark — native path (walk, with identity cache) | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| php -d extension="$NATIVE_EXT" tests/tools/run-native-ast-walk-benchmark.php | tee native-walk.txt | |
| - name: Check out baseline (PR base, no identity cache) | |
| run: | | |
| git fetch --no-tags --depth=1 origin codex/native-lazy-ast-facade | |
| git worktree add ../baseline FETCH_HEAD | |
| - name: Install Composer dependencies (baseline mysql-on-sqlite) | |
| uses: ramsey/composer-install@v3 | |
| with: | |
| working-directory: ../baseline/packages/mysql-on-sqlite | |
| ignore-cache: "yes" | |
| composer-options: "--optimize-autoloader" | |
| - name: Build baseline parser extension (release) | |
| run: cargo build --release | |
| working-directory: ../baseline/packages/php-ext-wp-mysql-parser | |
| - name: Stage benchmark + corpus into baseline | |
| run: | | |
| mkdir -p ../baseline/packages/mysql-on-sqlite/tests/mysql/data | |
| cp packages/mysql-on-sqlite/tests/tools/run-native-ast-walk-benchmark.php \ | |
| ../baseline/packages/mysql-on-sqlite/tests/tools/ | |
| cp packages/mysql-on-sqlite/tests/mysql/data/*.csv \ | |
| ../baseline/packages/mysql-on-sqlite/tests/mysql/data/ 2>/dev/null || true | |
| - name: Benchmark — baseline native path (walk, no identity cache) | |
| working-directory: ../baseline/packages/mysql-on-sqlite | |
| run: | | |
| BASE_EXT="$(realpath ../../packages/php-ext-wp-mysql-parser/target/release/libwp_mysql_parser.so)" | |
| php -d extension="$BASE_EXT" tests/tools/run-native-ast-walk-benchmark.php \ | |
| | tee "$GITHUB_WORKSPACE/packages/mysql-on-sqlite/baseline-native-walk.txt" | |
| - name: Benchmark — baseline native path (parse only) | |
| working-directory: ../baseline/packages/mysql-on-sqlite | |
| run: | | |
| BASE_EXT="$(realpath ../../packages/php-ext-wp-mysql-parser/target/release/libwp_mysql_parser.so)" | |
| php -d extension="$BASE_EXT" tests/tools/run-native-ast-walk-benchmark.php --no-walk \ | |
| | tee "$GITHUB_WORKSPACE/packages/mysql-on-sqlite/baseline-native-parse-only.txt" | |
| # Hit-heavy scenarios — these are where the per-AST identity cache is | |
| # supposed to win. The baseline reallocates wrappers on every accessor | |
| # call, while the PR reuses them. Run on both to make the gap visible. | |
| - name: Benchmark — native rewalk x10 (this PR) | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| php -d extension="$NATIVE_EXT" tests/tools/run-native-ast-walk-benchmark.php --mode=rewalk --repeat=10 \ | |
| | tee native-rewalk.txt | |
| - name: Benchmark — baseline rewalk x10 | |
| working-directory: ../baseline/packages/mysql-on-sqlite | |
| run: | | |
| BASE_EXT="$(realpath ../../packages/php-ext-wp-mysql-parser/target/release/libwp_mysql_parser.so)" | |
| php -d extension="$BASE_EXT" tests/tools/run-native-ast-walk-benchmark.php --mode=rewalk --repeat=10 \ | |
| | tee "$GITHUB_WORKSPACE/packages/mysql-on-sqlite/baseline-native-rewalk.txt" | |
| - name: Benchmark — native reread x20 (this PR) | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| php -d extension="$NATIVE_EXT" tests/tools/run-native-ast-walk-benchmark.php --mode=reread --repeat=20 \ | |
| | tee native-reread.txt | |
| - name: Benchmark — baseline reread x20 | |
| working-directory: ../baseline/packages/mysql-on-sqlite | |
| run: | | |
| BASE_EXT="$(realpath ../../packages/php-ext-wp-mysql-parser/target/release/libwp_mysql_parser.so)" | |
| php -d extension="$BASE_EXT" tests/tools/run-native-ast-walk-benchmark.php --mode=reread --repeat=20 \ | |
| | tee "$GITHUB_WORKSPACE/packages/mysql-on-sqlite/baseline-native-reread.txt" | |
| - name: Benchmark — native subtree x5 (this PR) | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| php -d extension="$NATIVE_EXT" tests/tools/run-native-ast-walk-benchmark.php --mode=subtree --repeat=5 \ | |
| | tee native-subtree.txt | |
| - name: Benchmark — baseline subtree x5 | |
| working-directory: ../baseline/packages/mysql-on-sqlite | |
| run: | | |
| BASE_EXT="$(realpath ../../packages/php-ext-wp-mysql-parser/target/release/libwp_mysql_parser.so)" | |
| php -d extension="$BASE_EXT" tests/tools/run-native-ast-walk-benchmark.php --mode=subtree --repeat=5 \ | |
| | tee "$GITHUB_WORKSPACE/packages/mysql-on-sqlite/baseline-native-subtree.txt" | |
| - name: Summarize | |
| if: always() | |
| working-directory: packages/mysql-on-sqlite | |
| run: | | |
| extract() { | |
| # Pull a numeric field (e.g. duration=1.23s) from a benchmark | |
| # output line. Returns "n/a" if missing. | |
| local file="$1" key="$2" | |
| [ -f "$file" ] || { echo "n/a"; return; } | |
| grep -oE "${key}=[^ ]+" "$file" | head -1 | cut -d= -f2 || echo "n/a" | |
| } | |
| { | |
| echo '### Native AST walk perf' | |
| echo | |
| echo '| scenario | result |' | |
| echo '|---|---|' | |
| for f in php-parse-only.txt php-walk.txt native-parse-only.txt native-walk.txt baseline-native-parse-only.txt baseline-native-walk.txt native-rewalk.txt baseline-native-rewalk.txt native-reread.txt baseline-native-reread.txt native-subtree.txt baseline-native-subtree.txt; do | |
| [ -f "$f" ] || continue | |
| line="$(cat "$f")" | |
| echo "| ${f%.txt} | \`$line\` |" | |
| done | |
| echo | |
| echo '### Identity-cache cost (native walk: with cache vs PR base without)' | |
| echo | |
| echo '| metric | with cache (this PR) | baseline | delta |' | |
| echo '|---|---|---|---|' | |
| for key in duration qps peak_mem walked_nodes; do | |
| with="$(extract native-walk.txt "$key")" | |
| base="$(extract baseline-native-walk.txt "$key")" | |
| echo "| $key | $with | $base | — |" | |
| done | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload raw output | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: native-ast-perf-${{ github.run_id }} | |
| path: packages/mysql-on-sqlite/*.txt | |
| if-no-files-found: warn |