Auto merge of #88219 - jyn514:parallel-io, r=GuillaumeGomez

rustdoc: reduce number of copies when using parallel IO

This is Windows-only for now; I was getting really bad slowdowns from this on linux for some reason.

Helps with https://github.com/rust-lang/rust/issues/82741. Follow-up to https://github.com/rust-lang/rust/pull/60971.
This commit is contained in:
bors 2021-09-16 13:47:55 +00:00
commit d1d8145dff
4 changed files with 53 additions and 45 deletions

View File

@ -11,7 +11,7 @@
use std::fs; use std::fs;
use std::io; use std::io;
use std::path::Path; use std::path::{Path, PathBuf};
use std::string::ToString; use std::string::ToString;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
@ -55,17 +55,17 @@ impl DocFS {
fs::create_dir_all(path) fs::create_dir_all(path)
} }
crate fn write<P, C, E>(&self, path: P, contents: C) -> Result<(), E> crate fn write<E>(
&self,
path: PathBuf,
contents: impl 'static + Send + AsRef<[u8]>,
) -> Result<(), E>
where where
P: AsRef<Path>,
C: AsRef<[u8]>,
E: PathError, E: PathError,
{ {
if !self.sync_only && cfg!(windows) { if !self.sync_only && cfg!(windows) {
// A possible future enhancement after more detailed profiling would // A possible future enhancement after more detailed profiling would
// be to create the file sync so errors are reported eagerly. // be to create the file sync so errors are reported eagerly.
let path = path.as_ref().to_path_buf();
let contents = contents.as_ref().to_vec();
let sender = self.errors.clone().expect("can't write after closing"); let sender = self.errors.clone().expect("can't write after closing");
rayon::spawn(move || { rayon::spawn(move || {
fs::write(&path, contents).unwrap_or_else(|e| { fs::write(&path, contents).unwrap_or_else(|e| {

View File

@ -574,7 +574,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|buf: &mut Buffer| all.print(buf), |buf: &mut Buffer| all.print(buf),
&self.shared.style_files, &self.shared.style_files,
); );
self.shared.fs.write(final_file, v.as_bytes())?; self.shared.fs.write(final_file, v)?;
// Generating settings page. // Generating settings page.
page.title = "Rustdoc settings"; page.title = "Rustdoc settings";
@ -596,14 +596,14 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
)?, )?,
&style_files, &style_files,
); );
self.shared.fs.write(&settings_file, v.as_bytes())?; self.shared.fs.write(settings_file, v)?;
if let Some(ref redirections) = self.shared.redirections { if let Some(ref redirections) = self.shared.redirections {
if !redirections.borrow().is_empty() { if !redirections.borrow().is_empty() {
let redirect_map_path = let redirect_map_path =
self.dst.join(&*crate_name.as_str()).join("redirect-map.json"); self.dst.join(&*crate_name.as_str()).join("redirect-map.json");
let paths = serde_json::to_string(&*redirections.borrow()).unwrap(); let paths = serde_json::to_string(&*redirections.borrow()).unwrap();
self.shared.ensure_dir(&self.dst.join(&*crate_name.as_str()))?; self.shared.ensure_dir(&self.dst.join(&*crate_name.as_str()))?;
self.shared.fs.write(&redirect_map_path, paths.as_bytes())?; self.shared.fs.write(redirect_map_path, paths)?;
} }
} }
@ -641,7 +641,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
if !buf.is_empty() { if !buf.is_empty() {
self.shared.ensure_dir(&self.dst)?; self.shared.ensure_dir(&self.dst)?;
let joint_dst = self.dst.join("index.html"); let joint_dst = self.dst.join("index.html");
scx.fs.write(&joint_dst, buf.as_bytes())?; scx.fs.write(joint_dst, buf)?;
} }
// Render sidebar-items.js used throughout this module. // Render sidebar-items.js used throughout this module.
@ -653,7 +653,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
let items = self.build_sidebar_items(module); let items = self.build_sidebar_items(module);
let js_dst = self.dst.join("sidebar-items.js"); let js_dst = self.dst.join("sidebar-items.js");
let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap()); let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap());
scx.fs.write(&js_dst, &v)?; scx.fs.write(js_dst, v)?;
} }
Ok(()) Ok(())
} }
@ -687,7 +687,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
let file_name = &item_path(item_type, &name.as_str()); let file_name = &item_path(item_type, &name.as_str());
self.shared.ensure_dir(&self.dst)?; self.shared.ensure_dir(&self.dst)?;
let joint_dst = self.dst.join(file_name); let joint_dst = self.dst.join(file_name);
self.shared.fs.write(&joint_dst, buf.as_bytes())?; self.shared.fs.write(joint_dst, buf)?;
if !self.render_redirect_pages { if !self.render_redirect_pages {
self.shared.all.borrow_mut().append(full_path(self, &item), &item_type); self.shared.all.borrow_mut().append(full_path(self, &item), &item_type);
@ -705,7 +705,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
} else { } else {
let v = layout::redirect(file_name); let v = layout::redirect(file_name);
let redir_dst = self.dst.join(redir_name); let redir_dst = self.dst.join(redir_name);
self.shared.fs.write(&redir_dst, v.as_bytes())?; self.shared.fs.write(redir_dst, v)?;
} }
} }
} }

View File

@ -105,10 +105,10 @@ impl Context<'_> {
self.dst.join(&filename) self.dst.join(&filename)
} }
fn write_shared<C: AsRef<[u8]>>( fn write_shared(
&self, &self,
resource: SharedResource<'_>, resource: SharedResource<'_>,
contents: C, contents: impl 'static + Send + AsRef<[u8]>,
emit: &[EmitType], emit: &[EmitType],
) -> Result<(), Error> { ) -> Result<(), Error> {
if resource.should_emit(emit) { if resource.should_emit(emit) {
@ -121,25 +121,23 @@ impl Context<'_> {
fn write_minify( fn write_minify(
&self, &self,
resource: SharedResource<'_>, resource: SharedResource<'_>,
contents: &str, contents: impl 'static + Send + AsRef<str> + AsRef<[u8]>,
minify: bool, minify: bool,
emit: &[EmitType], emit: &[EmitType],
) -> Result<(), Error> { ) -> Result<(), Error> {
let tmp; if minify {
let contents = if minify { let contents = contents.as_ref();
tmp = if resource.extension() == Some(&OsStr::new("css")) { let contents = if resource.extension() == Some(&OsStr::new("css")) {
minifier::css::minify(contents).map_err(|e| { minifier::css::minify(contents).map_err(|e| {
Error::new(format!("failed to minify CSS file: {}", e), resource.path(self)) Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
})? })?
} else { } else {
minifier::js::minify(contents) minifier::js::minify(contents)
}; };
tmp.as_bytes() self.write_shared(resource, contents, emit)
} else { } else {
contents.as_bytes() self.write_shared(resource, contents, emit)
}; }
self.write_shared(resource, contents, emit)
} }
} }
@ -155,15 +153,21 @@ pub(super) fn write_shared(
let lock_file = cx.dst.join(".lock"); let lock_file = cx.dst.join(".lock");
let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file); let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file);
// The weird `: &_` is to work around a borrowck bug: https://github.com/rust-lang/rust/issues/41078#issuecomment-293646723 // Minified resources are usually toolchain resources. If they're not, they should use `cx.write_minify` directly.
let write_minify = |p, c: &_| { fn write_minify(
basename: &'static str,
contents: impl 'static + Send + AsRef<str> + AsRef<[u8]>,
cx: &Context<'_>,
options: &RenderOptions,
) -> Result<(), Error> {
cx.write_minify( cx.write_minify(
SharedResource::ToolchainSpecific { basename: p }, SharedResource::ToolchainSpecific { basename },
c, contents,
options.enable_minification, options.enable_minification,
&options.emit, &options.emit,
) )
}; }
// Toolchain resources should never be dynamic. // Toolchain resources should never be dynamic.
let write_toolchain = |p: &'static _, c: &'static _| { let write_toolchain = |p: &'static _, c: &'static _| {
cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c, &options.emit) cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c, &options.emit)
@ -210,12 +214,12 @@ pub(super) fn write_shared(
"details.undocumented > summary::before, details.rustdoc-toggle > summary::before", "details.undocumented > summary::before, details.rustdoc-toggle > summary::before",
"toggle-plus.svg", "toggle-plus.svg",
); );
write_minify("rustdoc.css", &rustdoc_css)?; write_minify("rustdoc.css", rustdoc_css, cx, options)?;
// Add all the static files. These may already exist, but we just // Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date. // overwrite them anyway to make sure that they're fresh and up-to-date.
write_minify("settings.css", static_files::SETTINGS_CSS)?; write_minify("settings.css", static_files::SETTINGS_CSS, cx, options)?;
write_minify("noscript.css", static_files::NOSCRIPT_CSS)?; write_minify("noscript.css", static_files::NOSCRIPT_CSS, cx, options)?;
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only // To avoid "light.css" to be overwritten, we'll first run over the received themes and only
// then we'll run over the "official" styles. // then we'll run over the "official" styles.
@ -228,9 +232,9 @@ pub(super) fn write_shared(
// Handle the official themes // Handle the official themes
match theme { match theme {
"light" => write_minify("light.css", static_files::themes::LIGHT)?, "light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?,
"dark" => write_minify("dark.css", static_files::themes::DARK)?, "dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?,
"ayu" => write_minify("ayu.css", static_files::themes::AYU)?, "ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?,
_ => { _ => {
// Handle added third-party themes // Handle added third-party themes
let filename = format!("{}.{}", theme, extension); let filename = format!("{}.{}", theme, extension);
@ -264,26 +268,30 @@ pub(super) fn write_shared(
// Maybe we can change the representation to move this out of main.js? // Maybe we can change the representation to move this out of main.js?
write_minify( write_minify(
"main.js", "main.js",
&static_files::MAIN_JS.replace( static_files::MAIN_JS.replace(
"/* INSERT THEMES HERE */", "/* INSERT THEMES HERE */",
&format!(" = {}", serde_json::to_string(&themes).unwrap()), &format!(" = {}", serde_json::to_string(&themes).unwrap()),
), ),
cx,
options,
)?; )?;
write_minify("search.js", static_files::SEARCH_JS)?; write_minify("search.js", static_files::SEARCH_JS, cx, options)?;
write_minify("settings.js", static_files::SETTINGS_JS)?; write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?;
if cx.include_sources { if cx.include_sources {
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?; write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?;
} }
{ {
write_minify( write_minify(
"storage.js", "storage.js",
&format!( format!(
"var resourcesSuffix = \"{}\";{}", "var resourcesSuffix = \"{}\";{}",
cx.shared.resource_suffix, cx.shared.resource_suffix,
static_files::STORAGE_JS static_files::STORAGE_JS
), ),
cx,
options,
)?; )?;
} }
@ -292,12 +300,12 @@ pub(super) fn write_shared(
// This varies based on the invocation, so it can't go through the write_minify wrapper. // This varies based on the invocation, so it can't go through the write_minify wrapper.
cx.write_minify( cx.write_minify(
SharedResource::InvocationSpecific { basename: "theme.css" }, SharedResource::InvocationSpecific { basename: "theme.css" },
&buffer, buffer,
options.enable_minification, options.enable_minification,
&options.emit, &options.emit,
)?; )?;
} }
write_minify("normalize.css", static_files::NORMALIZE_CSS)?; write_minify("normalize.css", static_files::NORMALIZE_CSS, cx, options)?;
for (name, contents) in &*FILES_UNVERSIONED { for (name, contents) in &*FILES_UNVERSIONED {
cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?; cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?;
} }
@ -512,7 +520,7 @@ pub(super) fn write_shared(
content, content,
&cx.shared.style_files, &cx.shared.style_files,
); );
cx.shared.fs.write(&dst, v.as_bytes())?; cx.shared.fs.write(dst, v)?;
} }
} }
@ -603,7 +611,7 @@ pub(super) fn write_shared(
}", }",
); );
v.push_str("})()"); v.push_str("})()");
cx.shared.fs.write(&mydst, &v)?; cx.shared.fs.write(mydst, v)?;
} }
Ok(()) Ok(())
} }

View File

@ -208,7 +208,7 @@ impl SourceCollector<'_, 'tcx> {
}, },
&self.cx.shared.style_files, &self.cx.shared.style_files,
); );
self.cx.shared.fs.write(&cur, v.as_bytes())?; self.cx.shared.fs.write(cur, v)?;
self.emitted_local_sources.insert(p); self.emitted_local_sources.insert(p);
Ok(()) Ok(())
} }