Skip to content

bench: Bisect perf regressions #1884

bench: Bisect perf regressions

bench: Bisect perf regressions #1884

Workflow file for this run

name: CI
permissions: {}
on:
push: { branches: [main] }
pull_request:
concurrency:
# Make sure that new pushes cancel running jobs
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
LIBM_BUILD_VERBOSE: true
RUSTDOCFLAGS: -Dwarnings
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: full
BENCHMARK_RUSTC: nightly-2026-08-01 # Pin the toolchain for reproducable results
defaults:
run:
# Add `-ux` to the default template specified at
# https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#defaultsrunshell
shell: bash --noprofile --norc -euxo pipefail {0}
jobs:
# Determine which tests should be run based on changed files.
calculate_vars:
name: Calculate workflow variables
runs-on: ubuntu-24.04
timeout-minutes: 10
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
outputs:
extensive_matrix: ${{ steps.script.outputs.extensive_matrix }}
may_skip_libm_ci: ${{ steps.script.outputs.may_skip_libm_ci }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
fetch-depth: 500
- name: Fetch pull request ref
run: git fetch origin "$GITHUB_REF:$GITHUB_REF"
if: github.event_name == 'pull_request'
- run: |
set -eo pipefail # Needed to actually fail the job if ci-util fails
python3 ci/ci-util.py generate-matrix | tee "$GITHUB_OUTPUT"
id: script
# test:
# name: Build and test
# timeout-minutes: 60
# # NOTE: self-hosted riscv64 runners are experimental and may be flaky.
# # Do not block CI on failures from this platform for now.
# continue-on-error: ${{ contains(matrix.os, 'self-hosted') }}
# strategy:
# fail-fast: false
# matrix:
# include:
# - target: aarch64-apple-darwin
# os: macos-15
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# - target: aarch64-pc-windows-msvc
# os: windows-11-arm
# - target: arm-unknown-linux-gnueabi
# os: ubuntu-24.04
# - target: arm-unknown-linux-gnueabihf
# os: ubuntu-24.04
# - target: armv7-unknown-linux-gnueabihf
# os: ubuntu-24.04
# - target: i586-unknown-linux-gnu
# os: ubuntu-24.04
# - target: i686-unknown-linux-gnu
# os: ubuntu-24.04
# - target: loongarch64-unknown-linux-gnu
# os: ubuntu-24.04
# - target: powerpc-unknown-linux-gnu
# os: ubuntu-24.04
# - target: powerpc64-unknown-linux-gnu
# os: ubuntu-24.04
# - target: powerpc64-unknown-linux-musl
# os: ["self-hosted", "linux", "powerpc64", "musl"]
# - target: powerpc64le-unknown-linux-gnu
# os: ubuntu-24.04
# - target: powerpc64le-unknown-linux-gnu
# os: ubuntu-24.04-ppc64le
# # FIXME(ci): re-enable these once more capacity is avialable
# # - target: riscv64gc-unknown-linux-gnu
# # os: ["self-hosted", "linux", "riscv64"]
# - target: riscv64gc-unknown-linux-gnu
# os: ubuntu-24.04
# - target: s390x-unknown-linux-gnu
# os: ubuntu-24.04-s390x
# - target: thumbv6m-none-eabi
# os: ubuntu-24.04
# - target: thumbv7em-none-eabi
# os: ubuntu-24.04
# - target: thumbv7em-none-eabihf
# os: ubuntu-24.04
# - target: thumbv7m-none-eabi
# os: ubuntu-24.04
# - target: wasm32-unknown-unknown
# os: ubuntu-24.04
# - target: x86_64-unknown-linux-gnu
# os: ubuntu-24.04
# - target: x86_64-apple-darwin
# os: macos-15-intel
# - target: i686-pc-windows-msvc
# os: windows-2025
# - target: x86_64-pc-windows-msvc
# os: windows-2025
# - target: i686-pc-windows-gnu
# os: windows-2025
# channel: nightly-i686-gnu
# - target: x86_64-pc-windows-gnu
# os: windows-2025
# channel: nightly-x86_64-gnu
# runs-on: ${{ matrix.os }}
# needs: [calculate_vars]
# env:
# BUILD_ONLY: ${{ matrix.build_only }}
# JOB_TARGET: ${{ matrix.target }}
# JOB_CHANNEL: ${{ matrix.channel }}
# MAY_SKIP_LIBM_CI: ${{ needs.calculate_vars.outputs.may_skip_libm_ci }}
# RUN_IN_DOCKER: ${{ matrix.os == 'ubuntu-24.04' }}
# steps:
# - name: Print runner information
# run: |
# uname -a
# lscpu || (sysctl -a | grep cpu) || true
# echo "home: ${HOME:-not found}"
# pwd
# # Native ppc and s390x runners don't have rustup by default
# - name: Install rustup
# if: matrix.os == 'ubuntu-24.04-ppc64le' || matrix.os == 'ubuntu-24.04-s390x'
# run: sudo apt-get update && sudo apt-get install -y rustup
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - name: Install Rust (rustup)
# run: |
# channel="nightly"
# # Account for channels that have required components (MinGW)
# [ -n "$JOB_CHANNEL" ] && channel="$JOB_CHANNEL"
# rustup update "$channel" --no-self-update
# rustup default "$channel"
# rustup target add "$JOB_TARGET"
# - uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
# with:
# tool: nextest@0.9.131
# - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
# with:
# key: ${{ matrix.target }}
# - name: Cache Docker layers
# uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
# if: ${{ env.RUN_IN_DOCKER == 'true' }}
# with:
# path: /tmp/.buildx-cache
# key: ${{ matrix.target }}-buildx-${{ github.sha }}
# restore-keys: ${{ matrix.target }}-buildx-
# # Configure buildx to use Docker layer caching
# - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
# if: ${{ env.RUN_IN_DOCKER == 'true' }}
# - name: Cache compiler-rt
# id: cache-compiler-rt
# uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
# with:
# path: compiler-rt
# key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }}
# - name: Download compiler-rt reference sources
# if: steps.cache-compiler-rt.outputs.cache-hit != 'true'
# run: ./ci/download-compiler-rt.sh
# - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV"
# - name: Download musl source
# run: ./ci/update-musl.sh
# - name: Verify API list
# if: matrix.os == 'ubuntu-24.04' || contains(matrix.os, 'self-hosted')
# run: |
# # Must be run on the host (not in Docker) because git and fs access is required.
# python3 etc/update-api-list.py --check
# cargo test -p update-api-list
# # Non-linux tests just use our raw script
# - name: Run locally
# if: ${{ env.RUN_IN_DOCKER != 'true' }}
# run: ./ci/run.sh "$JOB_TARGET"
# # Otherwise we use our docker containers to run builds
# - name: Run in Docker
# if: ${{ env.RUN_IN_DOCKER == 'true' }}
# run: ./ci/run-docker.sh "$JOB_TARGET"
# - name: Print test logs if available
# if: always()
# run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi
# # Workaround to keep Docker cache smaller
# # https://github.com/docker/build-push-action/issues/252
# # https://github.com/moby/buildkit/issues/1896
# - name: Move Docker cache
# if: ${{ env.RUN_IN_DOCKER == 'true' }}
# run: |
# rm -rf /tmp/.buildx-cache
# mv /tmp/.buildx-cache-new /tmp/.buildx-cache
# clippy:
# name: Clippy
# runs-on: ubuntu-24.04
# timeout-minutes: 10
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# # Unlike rustfmt, stable clippy does not work on code with nightly features.
# - name: Install nightly `clippy`
# run: |
# rustup update nightly --no-self-update
# rustup default nightly
# rustup component add clippy
# - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
# - name: Download musl source
# run: ./ci/update-musl.sh
# - run: cargo clippy --workspace --all-targets
# zizmor:
# name: Zizmor (Static analysis for GitHub Actions)
# runs-on: ubuntu-24.04
# permissions:
# security-events: write
# timeout-minutes: 10
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
# build-custom:
# name: Build custom target
# runs-on: ubuntu-24.04
# timeout-minutes: 10
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - name: Install Rust
# run: |
# rustup update nightly --no-self-update
# rustup default nightly
# rustup component add rust-src
# - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
# - run: |
# # Ensure we can build with custom target.json files (these can interact
# # poorly with build scripts)
# cargo build -p compiler_builtins -p libm \
# --target etc/thumbv7em-none-eabi-renamed.json \
# -Zbuild-std=core \
# -Zjson-target-spec
# # FIXME: move this target to test job once https://github.com/rust-lang/rust/pull/150138 merged.
# build-thumbv6k:
# name: Build thumbv6k
# runs-on: ubuntu-24.04
# timeout-minutes: 10
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - name: Install Rust
# run: |
# rustup update nightly --no-self-update
# rustup default nightly
# rustup component add rust-src
# - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
# - run: |
# cargo build -p compiler_builtins -p libm \
# --target etc/thumbv6-none-eabi.json \
# -Zbuild-std=core \
# -Zjson-target-spec
benchmarks:
name: Benchmarks
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
# good
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-02-10
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-03-10
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-03-12
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-03-14
#
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
bench_rustc: nightly-2026-03-14
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
bench_rustc: nightly-2026-03-15
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
bench_rustc: nightly-2026-03-16
# bad 1
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-03-16
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-03-18
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-03-20
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-03-30
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-04-01
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-01
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-10
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-20
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-22
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
bench_rustc: nightly-2026-05-22
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
bench_rustc: nightly-2026-05-23
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
bench_rustc: nightly-2026-05-24
# bad 2
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-26
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-28
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-30
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-06-10
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-06-20
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-06-30
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-05-01
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-07-01
# - target: aarch64-unknown-linux-gnu
# os: ubuntu-24.04-arm
# bench_rustc: nightly-2026-08-01
# - target: i686-unknown-linux-gnu
# os: ubuntu-24.04
# - target: x86_64-unknown-linux-gnu
# os: ubuntu-24.04
runs-on: ${{ matrix.os }}
env:
JOB_TARGET: ${{ matrix.target }}
BENCHMARK_RUSTC: ${{ matrix.bench_rustc }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: { persist-credentials: false }
- uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
with:
tool: cargo-binstall@1.17.7
- name: Set up dependencies
run: ./ci/install-bench-deps.sh "$JOB_TARGET"
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
key: ${{ matrix.target }}
- name: Download musl source
run: ./ci/update-musl.sh
- name: Run icount benchmarks
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: ./ci/bench-icount.sh "$JOB_TARGET"
- name: Upload the benchmark baseline
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ env.BASELINE_NAME }}
path: ${{ env.BASELINE_NAME }}.tar.xz
- name: Print test logs if available
if: always()
run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi
# miri:
# name: Miri
# runs-on: ubuntu-24.04
# timeout-minutes: 10
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - name: Install Rust (rustup)
# run: rustup update nightly --no-self-update && rustup default nightly
# - run: rustup component add miri
# - run: cargo miri setup
# - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
# - run: ./ci/miri.sh
# msrv:
# name: Check libm MSRV
# runs-on: ubuntu-24.04
# timeout-minutes: 10
# env:
# RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings`
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - name: Install Rust
# run: |
# msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)"
# echo "MSRV: $msrv"
# rustup update "$msrv" --no-self-update && rustup default "$msrv"
# - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
# - run: |
# # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see
# # `edition = "2024"` and get spooked.
# rm Cargo.toml
# cargo build --manifest-path libm/Cargo.toml
# rustfmt:
# name: Rustfmt
# runs-on: ubuntu-24.04
# timeout-minutes: 10
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - name: Install nightly `rustfmt`
# run: rustup set profile minimal && rustup default nightly && rustup component add rustfmt
# - run: cargo fmt -- --check
# extensive:
# name: Extensive tests for ${{ matrix.ty }}
# needs:
# # Wait on `clippy` so we have some confidence that the crate will build
# - clippy
# - calculate_vars
# runs-on: ubuntu-24.04
# timeout-minutes: 240 # 4 hours
# strategy:
# matrix:
# # Use the output from `calculate_vars` to create the matrix
# # FIXME: it would be better to run all jobs (i.e. all types) but mark those that
# # didn't change as skipped, rather than completely excluding the job. However,
# # this is not currently possible https://github.com/actions/runner/issues/1985.
# include: ${{ fromJSON(needs.calculate_vars.outputs.extensive_matrix).extensive_matrix }}
# env:
# TO_TEST: ${{ matrix.to_test }}
# steps:
# - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# with: { persist-credentials: false }
# - name: Install Rust
# run: |
# rustup update nightly --no-self-update
# rustup default nightly
# - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
# - name: download musl source
# run: ./ci/update-musl.sh
# - name: Run extensive tests
# run: ./ci/run-extensive.sh
# - name: Print test logs if available
# run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi
success:
needs:
- benchmarks
# - build-custom
# - build-thumbv6k
# - clippy
# - extensive
# - miri
# - msrv
# - rustfmt
# - test
# - zizmor
runs-on: ubuntu-24.04
timeout-minutes: 10
# GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency
# failed" as success. So we have to do some contortions to ensure the job fails if any of its
# dependencies fails.
if: always() # make sure this is never "skipped"
env:
NEEDS: ${{ toJson(needs) }}
steps:
# Manually check the status of all dependencies. `if: failure()` does not work.
- name: check if any dependency failed
run: jq --exit-status 'all(.result == "success")' <<< "$NEEDS"