Skip to content

Rollup of 6 pull requests #97159

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

Merged
merged 14 commits into from
May 19, 2022
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
57 changes: 24 additions & 33 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ use rustc_attr as attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};

use rustc_data_structures::sync::par_iter;
#[cfg(parallel_compiler)]
use rustc_data_structures::sync::{par_iter, ParallelIterator};
use rustc_data_structures::sync::ParallelIterator;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
Expand Down Expand Up @@ -607,6 +608,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
second_half.iter().rev().interleave(first_half).copied().collect()
};

// Calculate the CGU reuse
let cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::<Vec<_>>()
});

let mut total_codegen_time = Duration::new(0, 0);
let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size());

// The non-parallel compiler can only translate codegen units to LLVM IR
// on a single thread, leading to a staircase effect where the N LLVM
// threads have to wait on the single codegen threads to generate work
Expand All @@ -617,8 +626,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// This likely is a temporary measure. Once we don't have to support the
// non-parallel compiler anymore, we can compile CGUs end-to-end in
// parallel and get rid of the complicated scheduling logic.
#[cfg(parallel_compiler)]
let pre_compile_cgus = |cgu_reuse: &[CguReuse]| {
let mut pre_compiled_cgus = if cfg!(parallel_compiler) {
tcx.sess.time("compile_first_CGU_batch", || {
// Try to find one CGU to compile per thread.
let cgus: Vec<_> = cgu_reuse
Expand All @@ -638,48 +646,31 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
})
.collect();

(pre_compiled_cgus, start_time.elapsed())
total_codegen_time += start_time.elapsed();

pre_compiled_cgus
})
} else {
FxHashMap::default()
};

#[cfg(not(parallel_compiler))]
let pre_compile_cgus = |_: &[CguReuse]| (FxHashMap::default(), Duration::new(0, 0));

let mut cgu_reuse = Vec::new();
let mut pre_compiled_cgus: Option<FxHashMap<usize, _>> = None;
let mut total_codegen_time = Duration::new(0, 0);
let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size());

for (i, cgu) in codegen_units.iter().enumerate() {
ongoing_codegen.wait_for_signal_to_codegen_item();
ongoing_codegen.check_for_errors(tcx.sess);

// Do some setup work in the first iteration
if pre_compiled_cgus.is_none() {
// Calculate the CGU reuse
cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect()
});
// Pre compile some CGUs
let (compiled_cgus, codegen_time) = pre_compile_cgus(&cgu_reuse);
pre_compiled_cgus = Some(compiled_cgus);
total_codegen_time += codegen_time;
}

let cgu_reuse = cgu_reuse[i];
tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);

match cgu_reuse {
CguReuse::No => {
let (module, cost) =
if let Some(cgu) = pre_compiled_cgus.as_mut().unwrap().remove(&i) {
cgu
} else {
let start_time = Instant::now();
let module = backend.compile_codegen_unit(tcx, cgu.name());
total_codegen_time += start_time.elapsed();
module
};
let (module, cost) = if let Some(cgu) = pre_compiled_cgus.remove(&i) {
cgu
} else {
let start_time = Instant::now();
let module = backend.compile_codegen_unit(tcx, cgu.name());
total_codegen_time += start_time.elapsed();
module
};
// This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
// guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
// compilation hang on post-monomorphization errors.
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ macro_rules! print {
/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)).
///
/// Use the [`format!`] syntax to write data to the standard output.
/// This macro uses the same syntax as [`format!`], but writes to the standard output instead.
/// See [`std::fmt`] for more information.
///
/// Use `println!` only for the primary output of your program. Use
Expand Down
13 changes: 0 additions & 13 deletions library/std/src/os/windows/io/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,19 +204,6 @@ impl OwnedHandle {
})?;
unsafe { Ok(Self::from_raw_handle(ret)) }
}

/// Allow child processes to inherit the handle.
#[cfg(not(target_vendor = "uwp"))]
pub(crate) fn set_inheritable(&self) -> io::Result<()> {
cvt(unsafe {
c::SetHandleInformation(
self.as_raw_handle(),
c::HANDLE_FLAG_INHERIT,
c::HANDLE_FLAG_INHERIT,
)
})?;
Ok(())
}
}

impl TryFrom<HandleOrInvalid> for OwnedHandle {
Expand Down
6 changes: 0 additions & 6 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1026,12 +1026,6 @@ extern "system" {
bWaitAll: BOOL,
dwMilliseconds: DWORD,
) -> DWORD;
pub fn CreatePipe(
hReadPipe: *mut HANDLE,
hWritePipe: *mut HANDLE,
lpPipeAttributes: *const SECURITY_ATTRIBUTES,
nSize: DWORD,
) -> BOOL;
pub fn CreateNamedPipeW(
lpName: LPCWSTR,
dwOpenMode: DWORD,
Expand Down
5 changes: 0 additions & 5 deletions library/std/src/sys/windows/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,6 @@ impl Handle {
Ok(Self(self.0.duplicate(access, inherit, options)?))
}

#[cfg(not(target_vendor = "uwp"))]
pub(crate) fn set_inheritable(&self) -> io::Result<()> {
self.0.set_inheritable()
}

/// Performs a synchronous read.
///
/// If the handle is opened for asynchronous I/O then this abort the process.
Expand Down
101 changes: 25 additions & 76 deletions library/std/src/sys/windows/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,67 +18,20 @@ use crate::sys_common::IntoInner;
// Anonymous pipes
////////////////////////////////////////////////////////////////////////////////

// A 64kb pipe capacity is the same as a typical Linux default.
const PIPE_BUFFER_CAPACITY: u32 = 64 * 1024;

pub enum AnonPipe {
Sync(Handle),
Async(Handle),
pub struct AnonPipe {
inner: Handle,
}

impl IntoInner<Handle> for AnonPipe {
fn into_inner(self) -> Handle {
match self {
Self::Sync(handle) => handle,
Self::Async(handle) => handle,
}
self.inner
}
}

pub struct Pipes {
pub ours: AnonPipe,
pub theirs: AnonPipe,
}
impl Pipes {
/// Create a new pair of pipes where both pipes are synchronous.
///
/// These must not be used asynchronously.
pub fn new_synchronous(
ours_readable: bool,
their_handle_inheritable: bool,
) -> io::Result<Self> {
unsafe {
// If `CreatePipe` succeeds, these will be our pipes.
let mut read = ptr::null_mut();
let mut write = ptr::null_mut();

if c::CreatePipe(&mut read, &mut write, ptr::null(), PIPE_BUFFER_CAPACITY) == 0 {
Err(io::Error::last_os_error())
} else {
let (ours, theirs) = if ours_readable { (read, write) } else { (write, read) };
let ours = Handle::from_raw_handle(ours);
#[cfg(not(target_vendor = "uwp"))]
let theirs = Handle::from_raw_handle(theirs);
#[cfg(target_vendor = "uwp")]
let mut theirs = Handle::from_raw_handle(theirs);

if their_handle_inheritable {
#[cfg(not(target_vendor = "uwp"))]
{
theirs.set_inheritable()?;
}

#[cfg(target_vendor = "uwp")]
{
theirs = theirs.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?;
}
}

Ok(Pipes { ours: AnonPipe::Sync(ours), theirs: AnonPipe::Sync(theirs) })
}
}
}
}

/// Although this looks similar to `anon_pipe` in the Unix module it's actually
/// subtly different. Here we'll return two pipes in the `Pipes` return value,
Expand All @@ -100,6 +53,9 @@ impl Pipes {
/// with `OVERLAPPED` instances, but also works out ok if it's only ever used
/// once at a time (which we do indeed guarantee).
pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result<Pipes> {
// A 64kb pipe capacity is the same as a typical Linux default.
const PIPE_BUFFER_CAPACITY: u32 = 64 * 1024;

// Note that we specifically do *not* use `CreatePipe` here because
// unfortunately the anonymous pipes returned do not support overlapped
// operations. Instead, we create a "hopefully unique" name and create a
Expand Down Expand Up @@ -200,9 +156,12 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
};
opts.security_attributes(&mut sa);
let theirs = File::open(Path::new(&name), &opts)?;
let theirs = AnonPipe::Sync(theirs.into_inner());
let theirs = AnonPipe { inner: theirs.into_inner() };

Ok(Pipes { ours: AnonPipe::Async(ours), theirs })
Ok(Pipes {
ours: AnonPipe { inner: ours },
theirs: AnonPipe { inner: theirs.into_inner() },
})
}
}

Expand All @@ -212,12 +171,12 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
/// This is achieved by creating a new set of pipes and spawning a thread that
/// relays messages between the source and the synchronous pipe.
pub fn spawn_pipe_relay(
source: &Handle,
source: &AnonPipe,
ours_readable: bool,
their_handle_inheritable: bool,
) -> io::Result<AnonPipe> {
// We need this handle to live for the lifetime of the thread spawned below.
let source = AnonPipe::Async(source.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?);
let source = source.duplicate()?;

// create a new pair of anon pipes.
let Pipes { theirs, ours } = anon_pipe(ours_readable, their_handle_inheritable)?;
Expand Down Expand Up @@ -268,24 +227,19 @@ type AlertableIoFn = unsafe extern "system" fn(

impl AnonPipe {
pub fn handle(&self) -> &Handle {
match self {
Self::Async(ref handle) => handle,
Self::Sync(ref handle) => handle,
}
&self.inner
}
pub fn into_handle(self) -> Handle {
self.into_inner()
self.inner
}
fn duplicate(&self) -> io::Result<Self> {
self.inner.duplicate(0, false, c::DUPLICATE_SAME_ACCESS).map(|inner| AnonPipe { inner })
}

pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let result = unsafe {
let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
match self {
Self::Sync(ref handle) => handle.read(buf),
Self::Async(_) => {
self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
}
}
self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
};

match result {
Expand All @@ -299,33 +253,28 @@ impl AnonPipe {
}

pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
io::default_read_vectored(|buf| self.read(buf), bufs)
self.inner.read_vectored(bufs)
}

#[inline]
pub fn is_read_vectored(&self) -> bool {
false
self.inner.is_read_vectored()
}

pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
match self {
Self::Sync(ref handle) => handle.write(buf),
Self::Async(_) => {
self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
}
}
self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
}
}

pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
io::default_write_vectored(|buf| self.write(buf), bufs)
self.inner.write_vectored(bufs)
}

#[inline]
pub fn is_write_vectored(&self) -> bool {
false
self.inner.is_write_vectored()
}

/// Synchronizes asynchronous reads or writes using our anonymous pipe.
Expand Down Expand Up @@ -397,7 +346,7 @@ impl AnonPipe {

// Asynchronous read of the pipe.
// If successful, `callback` will be called once it completes.
let result = io(self.handle().as_handle(), buf, len, &mut overlapped, callback);
let result = io(self.inner.as_handle(), buf, len, &mut overlapped, callback);
if result == c::FALSE {
// We can return here because the call failed.
// After this we must not return until the I/O completes.
Expand Down
Loading