Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PGO for LLVM builds on x86_64-unknown-linux-gnu in CI #88069

Merged
merged 3 commits into from
Aug 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/bootstrap/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ pub struct Config {
pub rust_new_symbol_mangling: bool,
pub rust_profile_use: Option<String>,
pub rust_profile_generate: Option<String>,
pub llvm_profile_use: Option<String>,
pub llvm_profile_generate: bool,

pub build: TargetSelection,
pub hosts: Vec<TargetSelection>,
Expand Down Expand Up @@ -605,6 +607,8 @@ impl Config {
if let Some(value) = flags.deny_warnings {
config.deny_warnings = value;
}
config.llvm_profile_use = flags.llvm_profile_use;
config.llvm_profile_generate = flags.llvm_profile_generate;

if config.dry_run {
let dir = config.out.join("tmp-dry-run");
Expand Down
14 changes: 10 additions & 4 deletions src/bootstrap/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2157,10 +2157,16 @@ impl Step for ReproducibleArtifacts {
}

fn run(self, builder: &Builder<'_>) -> Self::Output {
let path = builder.config.rust_profile_use.as_ref()?;

let mut added_anything = false;
let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
tarball.add_file(path, ".", 0o644);
Some(tarball.generate())
if let Some(path) = builder.config.rust_profile_use.as_ref() {
tarball.add_file(path, ".", 0o644);
added_anything = true;
}
if let Some(path) = builder.config.llvm_profile_use.as_ref() {
tarball.add_file(path, ".", 0o644);
added_anything = true;
}
if added_anything { Some(tarball.generate()) } else { None }
}
}
2 changes: 1 addition & 1 deletion src/bootstrap/download-ci-llvm-stamp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Change this file to make users of the `download-ci-llvm` configuration download
a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.

Last change is for: https://github.com/rust-lang/rust/pull/80932
Last change is for: https://github.com/rust-lang/rust/pull/88069
20 changes: 18 additions & 2 deletions src/bootstrap/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ pub struct Flags {

pub rust_profile_use: Option<String>,
pub rust_profile_generate: Option<String>,

pub llvm_profile_use: Option<String>,
// LLVM doesn't support a custom location for generating profile
// information.
//
// llvm_out/build/profiles/ is the location this writes to.
pub llvm_profile_generate: bool,
}

pub enum Subcommand {
Expand Down Expand Up @@ -222,8 +229,15 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
VALUE overrides the skip-rebuild option in config.toml.",
"VALUE",
);
opts.optopt("", "rust-profile-generate", "generate PGO profile with rustc build", "FORMAT");
opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "FORMAT");
opts.optopt(
"",
"rust-profile-generate",
"generate PGO profile with rustc build",
"PROFILE",
);
opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "PROFILE");
opts.optflag("", "llvm-profile-generate", "generate PGO profile with llvm built for rustc");
opts.optopt("", "llvm-profile-use", "use PGO profile for llvm build", "PROFILE");

// We can't use getopt to parse the options until we have completed specifying which
// options are valid, but under the current implementation, some options are conditional on
Expand Down Expand Up @@ -687,6 +701,8 @@ Arguments:
.expect("`color` should be `always`, `never`, or `auto`"),
rust_profile_use: matches.opt_str("rust-profile-use"),
rust_profile_generate: matches.opt_str("rust-profile-generate"),
llvm_profile_use: matches.opt_str("llvm-profile-use"),
llvm_profile_generate: matches.opt_present("llvm-profile-generate"),
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ impl Step for Llvm {
.define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);

if builder.config.llvm_profile_generate {
cfg.define("LLVM_BUILD_INSTRUMENTED", "IR");
cfg.define("LLVM_BUILD_RUNTIME", "No");
}
if let Some(path) = builder.config.llvm_profile_use.as_ref() {
cfg.define("LLVM_PROFDATA_FILE", &path);
}

if target != "aarch64-apple-darwin" && !target.contains("windows") {
cfg.define("LLVM_ENABLE_ZLIB", "ON");
} else {
Expand Down
6 changes: 6 additions & 0 deletions src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
RUN ./build-clang.sh
ENV CC=clang CXX=clang++

ENV PERF_COMMIT 1e19fc4c6168d2f7596e512f42f358f245d8f09d
Mark-Simulacrum marked this conversation as resolved.
Show resolved Hide resolved
RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \
unzip perf.zip && \
mv rustc-perf-$PERF_COMMIT rustc-perf && \
rm perf.zip

COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh

Expand Down
6 changes: 5 additions & 1 deletion src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ cd clang-build
# include path, /rustroot/include, to clang's default include path.
INC="/rustroot/include:/usr/include"

# We need compiler-rt for the profile runtime (used later to PGO the LLVM build)
# but sanitizers aren't currently building. Since we don't need those, just
# disable them.
hide_output \
cmake ../llvm \
-DCMAKE_C_COMPILER=/rustroot/bin/gcc \
-DCMAKE_CXX_COMPILER=/rustroot/bin/g++ \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/rustroot \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DLLVM_TARGETS_TO_BUILD=X86 \
-DLLVM_ENABLE_PROJECTS="clang;lld" \
-DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt" \
pietroalbini marked this conversation as resolved.
Show resolved Hide resolved
-DC_INCLUDE_DIRS="$INC"

hide_output make -j$(nproc)
Expand Down
7 changes: 5 additions & 2 deletions src/ci/docker/scripts/sccache.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#!/bin/sh

# ignore-tidy-linelength

set -ex

case "$(uname -m)" in
x86_64)
url="https://ci-mirrors.rust-lang.org/rustc/2018-04-02-sccache-x86_64-unknown-linux-musl"
url="https://ci-mirrors.rust-lang.org/rustc/2021-08-24-sccache-v0.2.15-x86_64-unknown-linux-musl"
;;
aarch64)
url="https://ci-mirrors.rust-lang.org/rustc/2019-12-17-sccache-aarch64-unknown-linux-gnu"
url="https://ci-mirrors.rust-lang.org/rustc/2021-08-25-sccache-v0.2.15-aarch64-unknown-linux-musl"
;;
*)
echo "unsupported architecture: $(uname -m)"
Expand Down
96 changes: 47 additions & 49 deletions src/ci/pgo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,61 +5,59 @@ set -euxo pipefail
rm -rf /tmp/rustc-pgo

python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
--stage 2 library/std --rust-profile-generate=/tmp/rustc-pgo
--stage 2 library/std \
--rust-profile-generate=/tmp/rustc-pgo \
--llvm-profile-generate

# Profile libcore compilation in opt-level=0 and opt-level=3
RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
--crate-type=lib ../library/core/src/lib.rs

# Download and build a single-file stress test benchmark on perf.rust-lang.org.
function pgo_perf_benchmark {
local PERF=1e19fc4c6168d2f7596e512f42f358f245d8f09d
local github_prefix=https://raw.githubusercontent.com/rust-lang/rustc-perf/$PERF
local name=$1
local edition=$2
curl -o /tmp/$name.rs $github_prefix/collector/benchmarks/$name/src/lib.rs

RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=$edition \
--crate-type=lib /tmp/$name.rs
}

pgo_perf_benchmark externs 2018
pgo_perf_benchmark ctfe-stress-4 2018
pgo_perf_benchmark inflate 2015

cp -pri ../src/tools/cargo /tmp/cargo

# The Cargo repository does not have a Cargo.lock in it, as it relies on the
# lockfile already present in the rust-lang/rust monorepo. This decision breaks
# down when Cargo is built outside the monorepo though (like in this case),
# resulting in a build without any dependency locking.
#
# To ensure Cargo is built with locked dependencies even during PGO profiling
# the following command copies the monorepo's lockfile into the Cargo temporary
# directory. Cargo will *not* keep that lockfile intact, as it will remove all
# the dependencies Cargo itself doesn't rely on. Still, it will prevent
# building Cargo with arbitrary dependency versions.
#
# See #81378 for the bug that prompted adding this.
cp -p ../Cargo.lock /tmp/cargo

# Build cargo (with some flags)
function pgo_cargo {
RUSTC=./build/$PGO_HOST/stage2/bin/rustc \
./build/$PGO_HOST/stage0/bin/cargo $@ \
--manifest-path /tmp/cargo/Cargo.toml
}

# Build a couple different variants of Cargo
CARGO_INCREMENTAL=1 pgo_cargo check
echo 'pub fn barbarbar() {}' >> /tmp/cargo/src/cargo/lib.rs
CARGO_INCREMENTAL=1 pgo_cargo check
touch /tmp/cargo/src/cargo/lib.rs
CARGO_INCREMENTAL=1 pgo_cargo check
pgo_cargo build --release
RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
--crate-type=lib -Copt-level=3 ../library/core/src/lib.rs

cp -r /tmp/rustc-perf ./
chown -R $(whoami): ./rustc-perf
cd rustc-perf

# Build the collector ahead of time, which is needed to make sure the rustc-fake
# binary used by the collector is present.
RUSTC=/checkout/obj/build/$PGO_HOST/stage0/bin/rustc \
RUSTC_BOOTSTRAP=1 \
/checkout/obj/build/$PGO_HOST/stage0/bin/cargo build -p collector
pietroalbini marked this conversation as resolved.
Show resolved Hide resolved

# benchmark using profile_local with eprintln, which essentially just means
# don't actually benchmark -- just make sure we run rustc a bunch of times.
RUST_LOG=collector=debug \
RUSTC=/checkout/obj/build/$PGO_HOST/stage0/bin/rustc \
RUSTC_BOOTSTRAP=1 \
/checkout/obj/build/$PGO_HOST/stage0/bin/cargo run -p collector --bin collector -- \
profile_local \
eprintln \
/checkout/obj/build/$PGO_HOST/stage2/bin/rustc \
Test \
--builds Check,Debug,Opt \
--cargo /checkout/obj/build/$PGO_HOST/stage0/bin/cargo \
--runs All \
--include externs,ctfe-stress-4,inflate,cargo,token-stream-stress,match-stress-enum

cd /checkout/obj

# Merge the profile data we gathered
./build/$PGO_HOST/llvm/bin/llvm-profdata \
merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo

# Merge the profile data we gathered for LLVM
# Note that this uses the profdata from the clang we used to build LLVM,
# which likely has a different version than our in-tree clang.
/rustroot/bin/llvm-profdata \
merge -o /tmp/llvm-pgo.profdata ./build/$PGO_HOST/llvm/build/profiles

# Rustbuild currently doesn't support rebuilding LLVM when PGO options
# change (or any other llvm-related options); so just clear out the relevant
# directories ourselves.
rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld

# This produces the actual final set of artifacts.
$@ --rust-profile-use=/tmp/rustc-pgo.profdata
$@ \
--rust-profile-use=/tmp/rustc-pgo.profdata \
--llvm-profile-use=/tmp/llvm-pgo.profdata
2 changes: 1 addition & 1 deletion src/ci/scripts/install-sccache.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ IFS=$'\n\t'
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"

if isMacOS; then
curl -fo /usr/local/bin/sccache "${MIRRORS_BASE}/2018-04-02-sccache-x86_64-apple-darwin"
curl -fo /usr/local/bin/sccache "${MIRRORS_BASE}/2021-08-25-sccache-v0.2.15-x86_64-apple-darwin"
chmod +x /usr/local/bin/sccache
elif isWindows; then
mkdir -p sccache
Expand Down