perf(hash): memcpy loads, overlap tails, 4-lane stripes for mh (#211) #809
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: Test | |
| # Branches only — release tags are handled by release.yml. Running this on tag | |
| # pushes fired the full matrix needlessly and broke `trunk check`, which diffs | |
| # against `github.event.before` (the prior tag object, gone after a tag move). | |
| on: | |
| push: | |
| branches: ["**"] | |
| permissions: read-all | |
| jobs: | |
| trunk: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Trunk Check | |
| uses: trunk-io/trunk-action@v1 | |
| - name: Trunk must not own git hooks | |
| run: | | |
| # Git hooks belong to pre-commit (see .pre-commit-config.yaml); trunk's | |
| # git-hook actions are disabled in .trunk/trunk.yaml so trunk never | |
| # clobbers pre-commit's clang-format run. This can only be checked here: | |
| # a pre-commit hook can't (if trunk owned core.hooksPath, pre-commit | |
| # would never run), and a trunk linter can't (it runs in an isolated | |
| # sandbox blind to the real git config). | |
| # 1) Config invariant: no trunk git-hook action may be enabled. | |
| enabled="$(yq -r '.actions.enabled // [] | .[]' .trunk/trunk.yaml)" | |
| for action in trunk-announce trunk-check-pre-commit trunk-check-pre-push \ | |
| trunk-check-pre-push-always trunk-fmt-pre-commit trufflehog-pre-commit; do | |
| if grep -qxF "${action}" <<<"${enabled}"; then | |
| echo "::error::trunk git-hook action '${action}' is enabled in .trunk/trunk.yaml; disable it so pre-commit keeps ownership of git hooks" | |
| exit 1 | |
| fi | |
| done | |
| # 2) Runtime truth (when trunk is available): sync hooks, then require | |
| # core.hooksPath not point back into trunk's cache. | |
| if command -v trunk >/dev/null 2>&1; then | |
| trunk git-hooks sync 2>&1 || true | |
| hooks_path="$(git config --get core.hooksPath || true)" | |
| if [[ "${hooks_path}" == *trunk* ]]; then | |
| echo "::error::core.hooksPath is trunk-managed (${hooks_path}); trunk grabbed the git hooks" | |
| exit 1 | |
| fi | |
| fi | |
| echo "OK: pre-commit owns git hooks; trunk is not managing them" | |
| pre-commit: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.13" | |
| - uses: pre-commit/action@v3.0.1 | |
| - uses: pre-commit-ci/lite-action@v1.0.2 | |
| if: always() | |
| benchmark: | |
| # Informational only (hence continue-on-error): shared runners are noisy, so | |
| # these numbers are for architecture/compiler shape comparisons (x86_64 gcc | |
| # vs arm64 Apple clang) and gross regressions, not precise gating. Results | |
| # appear in the job log and as a JSON artifact per OS. | |
| continue-on-error: true | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-26] | |
| runs-on: ${{matrix.os}} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: bazelbuild/setup-bazelisk@v3 | |
| - name: Run hash benchmark | |
| run: | | |
| bazel run -c opt //mbo/hash:hash_benchmark -- \ | |
| --benchmark_min_time=0.2s \ | |
| --benchmark_repetitions=3 \ | |
| --benchmark_report_aggregates_only=true \ | |
| --benchmark_out="${GITHUB_WORKSPACE}/hash_benchmark.json" \ | |
| --benchmark_out_format=json | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: hash-benchmark-${{matrix.os}} | |
| path: hash_benchmark.json | |
| test-gcc: | |
| needs: pre-commit | |
| secrets: inherit | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest] | |
| compiler: [gcc] | |
| gcc_version: [13, 14] | |
| bazel_config: [asan, cpp23, opt] | |
| # Using `include` does not make the options show up in the generated config names... | |
| exclude: | |
| - bazel_config: asan | |
| gcc_version: 13 | |
| - bazel_config: cpp23 | |
| gcc_version: 13 | |
| uses: ./.github/workflows/test.yml | |
| with: | |
| continue-on-error: false | |
| os: ${{ matrix.os }} | |
| compiler: ${{ matrix.compiler }} | |
| gcc_version: ${{ matrix.gcc_version }} | |
| bazel_config: ${{ matrix.bazel_config }} | |
| test-bcr: | |
| needs: [pre-commit, test-gcc] | |
| secrets: inherit | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-26] | |
| compiler: [gcc, native, clang] | |
| gcc_version: [13] | |
| llvm_version: [20.1.8] | |
| bazel_config: [opt] | |
| # Bazel-version compatibility rungs, crossed with the os/compiler combos | |
| # below. 7.2.1 is the earliest 7.x that works: MODULE.bazel uses | |
| # `include()` (added in 7.2.0, so 7.1.x fails with "name 'include' is not | |
| # defined") and the dep `depend_on_what_you_use@0.16.0` declares | |
| # `bazel_compatibility: [>=7.2.1]` (so 7.2.0 is rejected too). Plus the | |
| # latest 8.x (8.7.0), the latest 9.0.x (9.0.2), and the checked-in | |
| # default 9.1.1. | |
| bazel_version: [7.2.1, 8.7.0, 9.0.2, 9.1.1] | |
| exclude: | |
| - os: ubuntu-latest | |
| compiler: native | |
| - os: macos-26 | |
| compiler: gcc | |
| uses: ./.github/workflows/test.yml | |
| with: | |
| continue-on-error: false | |
| os: ${{ matrix.os }} | |
| compiler: ${{ matrix.compiler }} | |
| gcc_version: ${{ matrix.gcc_version }} | |
| llvm_version: ${{ matrix.llvm_version }} | |
| bazel_config: ${{ matrix.bazel_config }} | |
| bazel_version: ${{ matrix.bazel_version }} | |
| test-clang: | |
| needs: [pre-commit, test-gcc, test-bcr] | |
| secrets: inherit | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-26] | |
| compiler: [clang] | |
| # Hermetic toolchains_llvm clang (independent of the runner's Apple clang). | |
| # Ladder: working default (20), macOS native match (21 = Apple clang 21), newest (22). | |
| # TODO(llvm-23): add 23.x here once released and listed in toolchains_llvm. | |
| llvm_version: [20.1.8, 21.1.8, 22.1.7] | |
| bazel_config: [asan, cpp23, fastbuild, opt] | |
| exclude: | |
| # macOS asan works via toolchains_llvm's @loader_path rpath fix for the | |
| # sanitizer runtime dylib (helly25 fork; upstream PR #767), on LLVM | |
| # 22.1.7. 20.1.8 still hangs in compiler-rt FindDynamicShadowStart on | |
| # macOS 26, so exclude only that combo; macOS asan rides the 22.1.7 rung. | |
| - os: macos-26 | |
| llvm_version: 20.1.8 | |
| bazel_config: asan | |
| # 20.1.8 is the default pin -> full config coverage | |
| # 21.1.8 less coverage, just check opt | |
| # 22.1.7 keep the complex configs, just drop fastbuild | |
| - llvm_version: 21.1.8 | |
| bazel_config: asan | |
| - llvm_version: 21.1.8 | |
| bazel_config: cpp23 | |
| - llvm_version: 21.1.8 | |
| bazel_config: fastbuild | |
| - llvm_version: 22.1.7 | |
| bazel_config: fastbuild | |
| uses: ./.github/workflows/test.yml | |
| with: | |
| continue-on-error: true | |
| os: ${{ matrix.os }} | |
| compiler: ${{ matrix.compiler }} | |
| llvm_version: ${{ matrix.llvm_version }} | |
| bazel_config: ${{ matrix.bazel_config }} | |
| done: | |
| needs: [trunk, pre-commit, benchmark, test-gcc, test-clang, test-bcr] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Ensure every job is wired into this gate | |
| env: | |
| NEEDS_JSON: ${{ toJSON(needs) }} | |
| run: | | |
| # Parse the workflow with a real YAML reader (yq) and fail if any | |
| # declared job (other than this gate) is absent from `needs` above, so | |
| # a newly added job cannot silently escape the required gate. | |
| declared="$(yq '.jobs | keys | .[]' .github/workflows/main.yml | | |
| grep -vx done | sort)" | |
| wired="$(jq -r 'keys[]' <<<"${NEEDS_JSON}" | sort)" | |
| missing="$(comm -23 <(printf '%s\n' "${declared}") <(printf '%s\n' "${wired}"))" | |
| if [[ -n "${missing}" ]]; then | |
| echo "Jobs declared in the workflow but missing from done.needs:" | |
| while read -r job; do | |
| echo " - ${job}" | |
| echo "::error title=Gate is missing a job::${job} not in done.needs" | |
| done <<<"${missing}" | |
| exit 1 | |
| fi | |
| echo "done covers all $(grep -c . <<<"${declared}") workflow jobs." | |
| - name: Fail if any dependency did not succeed | |
| if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') | |
| run: exit 1 |