about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <tmgross@umich.edu>2025-04-20 07:05:32 +0000
committerTrevor Gross <t.gross35@gmail.com>2025-04-20 04:24:24 -0400
commit8902f740da9566061c5b23000899e7908921370b (patch)
treea6b61bb55fa82c691d588551b9069d6a458ea2aa
parenta829d916b5555a5ef65d521e98488f32b5476d36 (diff)
downloadrust-8902f740da9566061c5b23000899e7908921370b.tar.gz
rust-8902f740da9566061c5b23000899e7908921370b.zip
ci: Skip testing libm in PRs if it did not change
Many contributions to compiler-builtins don't have any need to touch
libm, and could get by with the few minutes of CI for compiler-builtins
rather than the ~30 minutes for libm. We already have some scripts that
handle changed file detection, so expand its use to skip libm CI if it
doesn't need to run.
-rw-r--r--library/compiler-builtins/.github/workflows/main.yaml49
-rwxr-xr-xlibrary/compiler-builtins/ci/ci-util.py42
-rwxr-xr-xlibrary/compiler-builtins/ci/run-docker.sh1
-rwxr-xr-xlibrary/compiler-builtins/ci/run.sh11
4 files changed, 66 insertions, 37 deletions
diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml
index 95ed6a855f3..690cdc89b1c 100644
--- a/library/compiler-builtins/.github/workflows/main.yaml
+++ b/library/compiler-builtins/.github/workflows/main.yaml
@@ -16,6 +16,27 @@ env:
   BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results
 
 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@v4
+        with:
+          fetch-depth: 500
+      - name: Fetch pull request ref
+        run: git fetch origin "$GITHUB_REF:$GITHUB_REF"
+        if: github.event_name == 'pull_request'
+      - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT"
+        id: script
+
   test:
     name: Build and test
     timeout-minutes: 60
@@ -78,9 +99,11 @@ jobs:
           os: windows-2025
           channel: nightly-x86_64-gnu
     runs-on: ${{ matrix.os }}
+    needs: [calculate_vars]
     env:
       BUILD_ONLY: ${{ matrix.build_only }}
       TEST_VERBATIM: ${{ matrix.test_verbatim }}
+      MAY_SKIP_LIBM_CI: ${{ needs.calculate_vars.outputs.may_skip_libm_ci }}
     steps:
     - name: Print runner information
       run: uname -a
@@ -267,41 +290,21 @@ jobs:
       run: rustup set profile minimal && rustup default stable && rustup component add rustfmt
     - run: cargo fmt -- --check
 
-  # Determine which extensive tests should be run based on changed files.
-  calculate_extensive_matrix:
-    name: Calculate job matrix
-    runs-on: ubuntu-24.04
-    timeout-minutes: 10
-    env:
-      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      PR_NUMBER: ${{ github.event.pull_request.number }}
-    outputs:
-      matrix: ${{ steps.script.outputs.matrix }}
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 100
-      - name: Fetch pull request ref
-        run: git fetch origin "$GITHUB_REF:$GITHUB_REF"
-        if: github.event_name == 'pull_request'
-      - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT"
-        id: script
-
   extensive:
     name: Extensive tests for ${{ matrix.ty }}
     needs:
       # Wait on `clippy` so we have some confidence that the crate will build
       - clippy
-      - calculate_extensive_matrix
+      - calculate_vars
     runs-on: ubuntu-24.04
     timeout-minutes: 240 # 4 hours
     strategy:
       matrix:
-        # Use the output from `calculate_extensive_matrix` to calculate the 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_extensive_matrix.outputs.matrix).matrix }}
+        include: ${{ fromJSON(needs.calculate_vars.outputs.extensive_matrix).extensive_matrix }}
     env:
       TO_TEST: ${{ matrix.to_test }}
     steps:
diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py
index d9e402d6bd7..7486d6b4186 100755
--- a/library/compiler-builtins/ci/ci-util.py
+++ b/library/compiler-builtins/ci/ci-util.py
@@ -7,6 +7,7 @@ git history.
 
 import json
 import os
+import re
 import subprocess as sp
 import sys
 from dataclasses import dataclass
@@ -68,6 +69,10 @@ IGNORE_FILES = [
     "libm/src/math/arch/intrinsics.rs",
 ]
 
+# libm PR CI takes a long time and doesn't need to run unless relevant files have been
+# changed. Anything matching this regex pattern will trigger a run.
+TRIGGER_LIBM_PR_CI = ".*(libm|musl).*"
+
 TYPES = ["f16", "f32", "f64", "f128"]
 
 
@@ -116,7 +121,6 @@ class FunctionDef(TypedDict):
     type: str
 
 
-@dataclass
 class Context:
     gh_ref: str | None
     changed: list[Path]
@@ -142,7 +146,7 @@ class Context:
         # the PR number), and sets this as `GITHUB_REF`.
         ref = self.gh_ref
         eprint(f"using ref `{ref}`")
-        if ref is None or "merge" not in ref:
+        if not self.is_pr():
             # If the ref is not for `merge` then we are not in PR CI
             eprint("No diff available for ref")
             return
@@ -170,6 +174,10 @@ class Context:
         )
         self.changed = [Path(p) for p in textlist.splitlines()]
 
+    def is_pr(self) -> bool:
+        """Check if we are looking at a PR rather than a push."""
+        return self.gh_ref is not None and "merge" in self.gh_ref
+
     @staticmethod
     def _ignore_file(fname: str) -> bool:
         return any(fname.startswith(pfx) for pfx in IGNORE_FILES)
@@ -196,7 +204,16 @@ class Context:
 
         return ret
 
-    def make_workflow_output(self) -> str:
+    def may_skip_libm_ci(self) -> bool:
+        """If this is a PR and no libm files were changed, allow skipping libm
+        jobs."""
+
+        if self.is_pr():
+            return all(not re.match(TRIGGER_LIBM_PR_CI, str(f)) for f in self.changed)
+
+        return False
+
+    def emit_workflow_output(self):
         """Create a JSON object a list items for each type's changed files, if any
         did change, and the routines that were affected by the change.
         """
@@ -216,9 +233,10 @@ class Context:
                 eprint("Skipping all extensive tests")
 
         changed = self.changed_routines()
-        ret = []
+        matrix = []
         total_to_test = 0
 
+        # Figure out which extensive tests need to run
         for ty in TYPES:
             ty_changed = changed.get(ty, [])
             ty_to_test = [] if skip_tests else ty_changed
@@ -230,9 +248,14 @@ class Context:
                 "to_test": ",".join(ty_to_test),
             }
 
-            ret.append(item)
-        output = json.dumps({"matrix": ret}, separators=(",", ":"))
-        eprint(f"output: {output}")
+            matrix.append(item)
+
+        ext_matrix = json.dumps({"extensive_matrix": matrix}, separators=(",", ":"))
+        may_skip = str(self.may_skip_libm_ci()).lower()
+        print(f"extensive_matrix={ext_matrix}")
+        print(f"may_skip_libm_ci={may_skip}")
+        eprint(f"extensive_matrix={ext_matrix}")
+        eprint(f"may_skip_libm_ci={may_skip}")
         eprint(f"total extensive tests: {total_to_test}")
 
         if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD:
@@ -242,8 +265,6 @@ class Context:
             )
             exit(1)
 
-        return output
-
 
 def locate_baseline(flags: list[str]) -> None:
     """Find the most recent baseline from CI, download it if specified.
@@ -398,8 +419,7 @@ def main():
     match sys.argv[1:]:
         case ["generate-matrix"]:
             ctx = Context()
-            output = ctx.make_workflow_output()
-            print(f"matrix={output}")
+            ctx.emit_workflow_output()
         case ["locate-baseline", *flags]:
             locate_baseline(flags)
         case ["check-regressions", *args]:
diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh
index c4d3af55ddc..58838fadf3c 100755
--- a/library/compiler-builtins/ci/run-docker.sh
+++ b/library/compiler-builtins/ci/run-docker.sh
@@ -77,6 +77,7 @@ run() {
         -e CI \
         -e CARGO_TARGET_DIR=/builtins-target \
         -e CARGO_TERM_COLOR \
+        -e MAY_SKIP_LIBM_CI \
         -e RUSTFLAGS \
         -e RUST_BACKTRACE \
         -e RUST_COMPILER_RT_ROOT \
diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh
index 0ad99da19f0..68d13c130bc 100755
--- a/library/compiler-builtins/ci/run.sh
+++ b/library/compiler-builtins/ci/run.sh
@@ -174,6 +174,14 @@ done
 
 # Test libm
 
+# Make sure a simple build works
+cargo check -p libm --no-default-features --target "$target"
+
+if [ "${MAY_SKIP_LIBM_CI:-}" = "true" ]; then
+    echo "skipping libm PR CI"
+    exit
+fi
+
 mflags=()
 
 # We enumerate features manually.
@@ -226,9 +234,6 @@ case "$target" in
     *windows-gnu) mflags+=(--exclude libm-macros) ;;
 esac
 
-# Make sure a simple build works
-cargo check -p libm --no-default-features --target "$target"
-
 if [ "${BUILD_ONLY:-}" = "1" ]; then
     # If we are on targets that can't run tests, verify that we can build.
     cmd=(cargo build --target "$target" --package libm)