diff options
| author | The rustc-dev-guide Cronjob Bot <github-actions@github.com> | 2025-04-19 13:53:12 +0000 |
|---|---|---|
| committer | The rustc-dev-guide Cronjob Bot <github-actions@github.com> | 2025-04-19 13:53:12 +0000 |
| commit | 3b2302ec0d17cbc94ef68b15f0bb6524f8b67f3f (patch) | |
| tree | 05635b943c977eba01cebf3ef78d8a479e555de5 /src/ci | |
| parent | a0c64dce0d70d1be54a6fd7b7aa9ed37665ad998 (diff) | |
| parent | a7c39b68616668a45f0afd62849a1da7c8ad2516 (diff) | |
| download | rust-3b2302ec0d17cbc94ef68b15f0bb6524f8b67f3f.tar.gz rust-3b2302ec0d17cbc94ef68b15f0bb6524f8b67f3f.zip | |
Merge from rustc
Diffstat (limited to 'src/ci')
| -rw-r--r-- | src/ci/citool/Cargo.lock | 4 | ||||
| -rw-r--r-- | src/ci/citool/src/analysis.rs | 62 | ||||
| -rw-r--r-- | src/ci/citool/src/github.rs | 109 | ||||
| -rw-r--r-- | src/ci/citool/src/main.rs | 11 | ||||
| -rw-r--r-- | src/ci/citool/tests/test-jobs.yml | 2 | ||||
| -rw-r--r-- | src/ci/docker/host-x86_64/mingw-check/Dockerfile | 1 | ||||
| -rw-r--r-- | src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile | 69 | ||||
| -rw-r--r-- | src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 1 | ||||
| -rw-r--r-- | src/ci/github-actions/jobs.yml | 39 |
9 files changed, 270 insertions, 28 deletions
diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index 800eaae0766..2fe219f368b 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -563,9 +563,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 7fbfad467c6..9fc7c309bfb 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -7,6 +7,7 @@ use build_helper::metrics::{ format_build_steps, }; +use crate::github::JobInfoResolver; use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; use crate::utils::{output_details, pluralize}; @@ -185,13 +186,19 @@ fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String { } /// Outputs a report of test differences between the `parent` and `current` commits. -pub fn output_test_diffs(job_metrics: &HashMap<JobName, JobMetrics>) { +pub fn output_test_diffs( + job_metrics: &HashMap<JobName, JobMetrics>, + job_info_resolver: &mut JobInfoResolver, +) { let aggregated_test_diffs = aggregate_test_diffs(&job_metrics); - report_test_diffs(aggregated_test_diffs); + report_test_diffs(aggregated_test_diffs, job_metrics, job_info_resolver); } /// Prints the ten largest differences in bootstrap durations. -pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics>) { +pub fn output_largest_duration_changes( + job_metrics: &HashMap<JobName, JobMetrics>, + job_info_resolver: &mut JobInfoResolver, +) { struct Entry<'a> { job: &'a JobName, before: Duration, @@ -225,14 +232,14 @@ pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics }); } } - changes.sort_by(|e1, e2| e1.change.partial_cmp(&e2.change).unwrap().reverse()); + changes.sort_by(|e1, e2| e1.change.abs().partial_cmp(&e2.change.abs()).unwrap().reverse()); println!("# Job duration changes"); for (index, entry) in changes.into_iter().take(10).enumerate() { println!( - "{}. `{}`: {:.1}s -> {:.1}s ({:.1}%)", + "{}. {}: {:.1}s -> {:.1}s ({:.1}%)", index + 1, - entry.job, + format_job_link(job_info_resolver, job_metrics, entry.job), entry.before.as_secs_f64(), entry.after.as_secs_f64(), entry.change @@ -400,7 +407,11 @@ fn generate_test_name(name: &str) -> String { } /// Prints test changes in Markdown format to stdout. -fn report_test_diffs(diff: AggregatedTestDiffs) { +fn report_test_diffs( + diff: AggregatedTestDiffs, + job_metrics: &HashMap<JobName, JobMetrics>, + job_info_resolver: &mut JobInfoResolver, +) { println!("# Test differences"); if diff.diffs.is_empty() { println!("No test diffs found"); @@ -509,21 +520,42 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { } if doctest_count > 0 { + let prefix = + if doctest_count < original_diff_count { "Additionally, " } else { "" }; println!( - "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.", + "\n{prefix}{doctest_count} doctest {} were found. These are ignored, as they are noisy.", pluralize("diff", doctest_count) ); } // Now print the job group index - println!("\n**Job group index**\n"); - for (group, jobs) in job_index.into_iter().enumerate() { - println!( - "- {}: {}", - format_job_group(group as u64), - jobs.iter().map(|j| format!("`{j}`")).collect::<Vec<_>>().join(", ") - ); + if !job_index.is_empty() { + println!("\n**Job group index**\n"); + for (group, jobs) in job_index.into_iter().enumerate() { + println!( + "- {}: {}", + format_job_group(group as u64), + jobs.iter() + .map(|j| format_job_link(job_info_resolver, job_metrics, j)) + .collect::<Vec<_>>() + .join(", ") + ); + } } }, ); } + +/// Tries to get a GitHub Actions job summary URL from the resolver. +/// If it is not available, just wraps the job name in backticks. +fn format_job_link( + job_info_resolver: &mut JobInfoResolver, + job_metrics: &HashMap<JobName, JobMetrics>, + job_name: &str, +) -> String { + job_metrics + .get(job_name) + .and_then(|metrics| job_info_resolver.get_job_summary_link(job_name, &metrics.current)) + .map(|summary_url| format!("[{job_name}]({summary_url})")) + .unwrap_or_else(|| format!("`{job_name}`")) +} diff --git a/src/ci/citool/src/github.rs b/src/ci/citool/src/github.rs new file mode 100644 index 00000000000..35e4c3f9599 --- /dev/null +++ b/src/ci/citool/src/github.rs @@ -0,0 +1,109 @@ +use std::collections::HashMap; + +use anyhow::Context; +use build_helper::metrics::{CiMetadata, JsonRoot}; + +pub struct GitHubClient; + +impl GitHubClient { + fn get_workflow_run_jobs( + &self, + repo: &str, + workflow_run_id: u64, + ) -> anyhow::Result<Vec<GitHubJob>> { + let req = ureq::get(format!( + "https://api.github.com/repos/{repo}/actions/runs/{workflow_run_id}/jobs?per_page=100" + )) + .header("User-Agent", "rust-lang/rust/citool") + .header("Accept", "application/vnd.github+json") + .header("X-GitHub-Api-Version", "2022-11-28") + .call() + .context("cannot get workflow job list")?; + + let status = req.status(); + let mut body = req.into_body(); + if status.is_success() { + // This API response is actually paged, but we assume for now that there are at + // most 100 jobs per workflow. + let response = body + .read_json::<WorkflowRunJobsResponse>() + .context("cannot deserialize workflow run jobs response")?; + // The CI job names have a prefix, e.g. `auto - foo`. We remove the prefix here to + // normalize the job name. + Ok(response + .jobs + .into_iter() + .map(|mut job| { + job.name = job + .name + .split_once(" - ") + .map(|res| res.1.to_string()) + .unwrap_or_else(|| job.name); + job + }) + .collect()) + } else { + Err(anyhow::anyhow!( + "Cannot get jobs of workflow run {workflow_run_id}: {status}\n{}", + body.read_to_string()? + )) + } + } +} + +#[derive(serde::Deserialize)] +struct WorkflowRunJobsResponse { + jobs: Vec<GitHubJob>, +} + +#[derive(serde::Deserialize)] +struct GitHubJob { + name: String, + id: u64, +} + +/// Can be used to resolve information about GitHub Actions jobs. +/// Caches results internally to avoid too unnecessary GitHub API calls. +pub struct JobInfoResolver { + client: GitHubClient, + // Workflow run ID -> jobs + workflow_job_cache: HashMap<u64, Vec<GitHubJob>>, +} + +impl JobInfoResolver { + pub fn new() -> Self { + Self { client: GitHubClient, workflow_job_cache: Default::default() } + } + + /// Get a link to a job summary for the given job name and bootstrap execution. + pub fn get_job_summary_link(&mut self, job_name: &str, metrics: &JsonRoot) -> Option<String> { + metrics.ci_metadata.as_ref().and_then(|metadata| { + self.get_job_id(metadata, job_name).map(|job_id| { + format!( + "https://github.com/{}/actions/runs/{}#summary-{job_id}", + metadata.repository, metadata.workflow_run_id + ) + }) + }) + } + + fn get_job_id(&mut self, ci_metadata: &CiMetadata, job_name: &str) -> Option<u64> { + if let Some(job) = self + .workflow_job_cache + .get(&ci_metadata.workflow_run_id) + .and_then(|jobs| jobs.iter().find(|j| j.name == job_name)) + { + return Some(job.id); + } + + let jobs = self + .client + .get_workflow_run_jobs(&ci_metadata.repository, ci_metadata.workflow_run_id) + .inspect_err(|e| eprintln!("Cannot download workflow jobs: {e:?}")) + .ok()?; + let job_id = jobs.iter().find(|j| j.name == job_name).map(|j| j.id); + // Save the cache even if the job name was not found, it could be useful for further lookups + self.workflow_job_cache.insert(ci_metadata.workflow_run_id, jobs); + job_id + } +} diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 6db5eab458c..a1956da352f 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -1,6 +1,7 @@ mod analysis; mod cpu_usage; mod datadog; +mod github; mod jobs; mod metrics; mod utils; @@ -18,6 +19,7 @@ use serde_yaml::Value; use crate::analysis::{output_largest_duration_changes, output_test_diffs}; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; +use crate::github::JobInfoResolver; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; use crate::utils::load_env_var; @@ -145,6 +147,7 @@ fn postprocess_metrics( ) -> anyhow::Result<()> { let metrics = load_metrics(&metrics_path)?; + let mut job_info_resolver = JobInfoResolver::new(); if let (Some(parent), Some(job_name)) = (parent, job_name) { // This command is executed also on PR builds, which might not have parent metrics // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics @@ -160,7 +163,7 @@ fn postprocess_metrics( job_name, JobMetrics { parent: Some(parent_metrics), current: metrics }, )]); - output_test_diffs(&job_metrics); + output_test_diffs(&job_metrics, &mut job_info_resolver); return Ok(()); } Err(error) => { @@ -180,8 +183,10 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow let metrics = download_auto_job_metrics(&db, &parent, ¤t)?; println!("\nComparing {parent} (parent) -> {current} (this PR)\n"); - output_test_diffs(&metrics); - output_largest_duration_changes(&metrics); + + let mut job_info_resolver = JobInfoResolver::new(); + output_test_diffs(&metrics, &mut job_info_resolver); + output_largest_duration_changes(&metrics, &mut job_info_resolver); Ok(()) } diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index 3593b3f7df6..d81be88b708 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 8bb7116c3ec..418408e9242 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -47,6 +47,7 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ ENV SCRIPT \ python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/check-default-config-profiles.sh && \ + python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py check --target=x86_64-pc-windows-gnu --host=x86_64-pc-windows-gnu && \ python3 ../x.py clippy ci && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile new file mode 100644 index 00000000000..408b87125e0 --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile @@ -0,0 +1,69 @@ +FROM ubuntu:25.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bzip2 \ + g++ \ + gcc-multilib \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-20-tools \ + llvm-20-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + xz-utils \ + nodejs \ + mingw-w64 \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install powershell (universal package) so we can test x.ps1 on Linux +# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep. +RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ + dpkg --ignore-depends=libicu72 -i powershell.deb && \ + rm -f powershell.deb + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# We are disabling CI LLVM since this builder is intentionally using a host +# LLVM, rather than the typical src/llvm-project LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 +ENV EXTERNAL_LLVM 1 + +# Using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-20 \ + --enable-llvm-link-shared \ + --set rust.randomize-layout=true \ + --set rust.thin-lto-import-instr-limit=10 + +COPY scripts/shared.sh /scripts/ + +ARG SCRIPT_ARG + +COPY scripts/add_dummy_commit.sh /tmp/ +COPY scripts/x86_64-gnu-llvm.sh /tmp/ +COPY scripts/x86_64-gnu-llvm2.sh /tmp/ +COPY scripts/x86_64-gnu-llvm3.sh /tmp/ +COPY scripts/stage_2_test_set1.sh /tmp/ +COPY scripts/stage_2_test_set2.sh /tmp/ + +ENV SCRIPT "/tmp/add_dummy_commit.sh && /tmp/${SCRIPT_ARG}" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 89806634c6c..05c90af7807 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -101,4 +101,5 @@ COPY scripts/shared.sh /scripts/ # the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ + python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 68e680a1b1b..cb2bec5a9df 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -23,8 +23,8 @@ runners: os: ubuntu-24.04-16core-64gb <<: *base-job - - &job-macos-xl - os: macos-13 # We use the standard runner for now + - &job-macos + os: macos-13 <<: *base-job - &job-macos-m1 @@ -58,7 +58,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. @@ -304,6 +304,31 @@ auto: - name: x86_64-gnu-distcheck <<: *job-linux-8c + # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel. + # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}. + - name: x86_64-gnu-llvm-20-1 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: stage_2_test_set1.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-20-{1,3} + - name: x86_64-gnu-llvm-20-2 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: x86_64-gnu-llvm2.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-20-{1,2} + - name: x86_64-gnu-llvm-20-3 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: x86_64-gnu-llvm3.sh + <<: *job-linux-4c + # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel. # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}. - name: x86_64-gnu-llvm-19-1 @@ -355,7 +380,7 @@ auto: NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift - <<: *job-macos-xl + <<: *job-macos - name: dist-apple-various env: @@ -372,18 +397,18 @@ auto: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl + <<: *job-macos - name: x86_64-apple-1 env: <<: *env-x86_64-apple-tests - <<: *job-macos-xl + <<: *job-macos - name: x86_64-apple-2 env: SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc <<: *env-x86_64-apple-tests - <<: *job-macos-xl + <<: *job-macos - name: dist-aarch64-apple env: |
