mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-25 11:17:13 +00:00
Merge pull request #19582 from Kobzol/ci-pgo
Distribute x64 and aarch64 Linux builds with PGO optimizations
This commit is contained in:
commit
6c589ef504
9
.github/workflows/release.yaml
vendored
9
.github/workflows/release.yaml
vendored
@ -38,10 +38,12 @@ jobs:
|
||||
target: x86_64-unknown-linux-gnu
|
||||
zig_target: x86_64-unknown-linux-gnu.2.28
|
||||
code-target: linux-x64
|
||||
pgo: true
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
zig_target: aarch64-unknown-linux-gnu.2.28
|
||||
code-target: linux-arm64
|
||||
pgo: true
|
||||
- os: ubuntu-latest
|
||||
target: arm-unknown-linux-gnueabihf
|
||||
zig_target: arm-unknown-linux-gnueabihf.2.28
|
||||
@ -74,7 +76,8 @@ jobs:
|
||||
- name: Install Rust toolchain
|
||||
run: |
|
||||
rustup update --no-self-update stable
|
||||
rustup component add rust-src
|
||||
# llvm-tools contain the llvm-profdata tool which is needed for PGO
|
||||
rustup component add rust-src ${{ matrix.pgo && 'llvm-tools' || '' }}
|
||||
rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: Install Zig toolchain
|
||||
@ -87,11 +90,11 @@ jobs:
|
||||
|
||||
- name: Dist (plain)
|
||||
if: ${{ !matrix.zig_target }}
|
||||
run: cargo xtask dist --client-patch-version ${{ github.run_number }}
|
||||
run: cargo xtask dist --client-patch-version ${{ github.run_number }} ${{ matrix.pgo && '--pgo' || ''}}
|
||||
|
||||
- name: Dist (using zigbuild)
|
||||
if: ${{ matrix.zig_target }}
|
||||
run: RA_TARGET=${{ matrix.zig_target}} cargo xtask dist --client-patch-version ${{ github.run_number }} --zig
|
||||
run: RA_TARGET=${{ matrix.zig_target}} cargo xtask dist --client-patch-version ${{ github.run_number }} --zig ${{ matrix.pgo && '--pgo' || ''}}
|
||||
|
||||
- run: npm ci
|
||||
working-directory: editors/code
|
||||
|
@ -1,13 +1,15 @@
|
||||
use anyhow::Context;
|
||||
use flate2::{Compression, write::GzEncoder};
|
||||
use std::env::consts::EXE_EXTENSION;
|
||||
use std::ffi::OsStr;
|
||||
use std::{
|
||||
env,
|
||||
fs::File,
|
||||
io::{self, BufWriter},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use flate2::{Compression, write::GzEncoder};
|
||||
use time::OffsetDateTime;
|
||||
use xshell::{Shell, cmd};
|
||||
use xshell::{Cmd, Shell, cmd};
|
||||
use zip::{DateTime, ZipWriter, write::SimpleFileOptions};
|
||||
|
||||
use crate::{
|
||||
@ -38,11 +40,18 @@ impl flags::Dist {
|
||||
// A hack to make VS Code prefer nightly over stable.
|
||||
format!("{VERSION_NIGHTLY}.{patch_version}")
|
||||
};
|
||||
dist_server(sh, &format!("{version}-standalone"), &target, allocator, self.zig)?;
|
||||
dist_server(
|
||||
sh,
|
||||
&format!("{version}-standalone"),
|
||||
&target,
|
||||
allocator,
|
||||
self.zig,
|
||||
self.pgo,
|
||||
)?;
|
||||
let release_tag = if stable { date_iso(sh)? } else { "nightly".to_owned() };
|
||||
dist_client(sh, &version, &release_tag, &target)?;
|
||||
} else {
|
||||
dist_server(sh, "0.0.0-standalone", &target, allocator, self.zig)?;
|
||||
dist_server(sh, "0.0.0-standalone", &target, allocator, self.zig, self.pgo)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -84,6 +93,7 @@ fn dist_server(
|
||||
target: &Target,
|
||||
allocator: Malloc,
|
||||
zig: bool,
|
||||
pgo: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let _e = sh.push_env("CFG_RELEASE", release);
|
||||
let _e = sh.push_env("CARGO_PROFILE_RELEASE_LTO", "thin");
|
||||
@ -100,7 +110,22 @@ fn dist_server(
|
||||
};
|
||||
let features = allocator.to_features();
|
||||
let command = if linux_target && zig { "zigbuild" } else { "build" };
|
||||
cmd!(sh, "cargo {command} --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release").run()?;
|
||||
|
||||
let pgo_profile = if pgo {
|
||||
Some(gather_pgo_profile(
|
||||
sh,
|
||||
build_command(sh, command, &target_name, features),
|
||||
&target_name,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut cmd = build_command(sh, command, &target_name, features);
|
||||
if let Some(profile) = pgo_profile {
|
||||
cmd = cmd.env("RUSTFLAGS", format!("-Cprofile-use={}", profile.to_str().unwrap()));
|
||||
}
|
||||
cmd.run().context("cannot build Rust Analyzer")?;
|
||||
|
||||
let dst = Path::new("dist").join(&target.artifact_name);
|
||||
if target_name.contains("-windows-") {
|
||||
@ -112,6 +137,70 @@ fn dist_server(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_command<'a>(
|
||||
sh: &'a Shell,
|
||||
command: &str,
|
||||
target_name: &str,
|
||||
features: &[&str],
|
||||
) -> Cmd<'a> {
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo {command} --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release"
|
||||
)
|
||||
}
|
||||
|
||||
/// Decorates `ra_build_cmd` to add PGO instrumentation, and then runs the PGO instrumented
|
||||
/// Rust Analyzer on itself to gather a PGO profile.
|
||||
fn gather_pgo_profile<'a>(
|
||||
sh: &'a Shell,
|
||||
ra_build_cmd: Cmd<'a>,
|
||||
target: &str,
|
||||
) -> anyhow::Result<PathBuf> {
|
||||
let pgo_dir = std::path::absolute("ra-pgo-profiles")?;
|
||||
// Clear out any stale profiles
|
||||
if pgo_dir.is_dir() {
|
||||
std::fs::remove_dir_all(&pgo_dir)?;
|
||||
}
|
||||
std::fs::create_dir_all(&pgo_dir)?;
|
||||
|
||||
// Figure out a path to `llvm-profdata`
|
||||
let target_libdir = cmd!(sh, "rustc --print=target-libdir")
|
||||
.read()
|
||||
.context("cannot resolve target-libdir from rustc")?;
|
||||
let target_bindir = PathBuf::from(target_libdir).parent().unwrap().join("bin");
|
||||
let llvm_profdata = target_bindir.join(format!("llvm-profdata{}", EXE_EXTENSION));
|
||||
|
||||
// Build RA with PGO instrumentation
|
||||
let cmd_gather =
|
||||
ra_build_cmd.env("RUSTFLAGS", format!("-Cprofile-generate={}", pgo_dir.to_str().unwrap()));
|
||||
cmd_gather.run().context("cannot build rust-analyzer with PGO instrumentation")?;
|
||||
|
||||
// Run RA on itself to gather profiles
|
||||
let train_crate = ".";
|
||||
cmd!(
|
||||
sh,
|
||||
"target/{target}/release/rust-analyzer analysis-stats {train_crate} --run-all-ide-things"
|
||||
)
|
||||
.run()
|
||||
.context("cannot generate PGO profiles")?;
|
||||
|
||||
// Merge profiles into a single file
|
||||
let merged_profile = pgo_dir.join("merged.profdata");
|
||||
let profile_files = std::fs::read_dir(pgo_dir)?.filter_map(|entry| {
|
||||
let entry = entry.ok()?;
|
||||
if entry.path().extension() == Some(OsStr::new("profraw")) {
|
||||
Some(entry.path().to_str().unwrap().to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
cmd!(sh, "{llvm_profdata} merge {profile_files...} -o {merged_profile}").run().context(
|
||||
"cannot merge PGO profiles. Do you have the rustup `llvm-tools` component installed?",
|
||||
)?;
|
||||
|
||||
Ok(merged_profile)
|
||||
}
|
||||
|
||||
fn gzip(src_path: &Path, dest_path: &Path) -> anyhow::Result<()> {
|
||||
let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
|
||||
let mut input = io::BufReader::new(File::open(src_path)?);
|
||||
|
@ -59,6 +59,8 @@ xflags::xflags! {
|
||||
optional --client-patch-version version: String
|
||||
/// Use cargo-zigbuild
|
||||
optional --zig
|
||||
/// Apply PGO optimizations
|
||||
optional --pgo
|
||||
}
|
||||
/// Read a changelog AsciiDoc file and update the GitHub Releases entry in Markdown.
|
||||
cmd publish-release-notes {
|
||||
@ -147,6 +149,7 @@ pub struct Dist {
|
||||
pub jemalloc: bool,
|
||||
pub client_patch_version: Option<String>,
|
||||
pub zig: bool,
|
||||
pub pgo: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user