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

Parallel formatting to increase speed #6095

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Pre dump
  • Loading branch information
MarcusGrass committed Feb 26, 2024
commit 1c3f95564f69b49ead084a639acdd2a22690ef81
28 changes: 28 additions & 0 deletions Progress.md
Original file line number Diff line number Diff line change
@@ -0,0 1,28 @@
# Multithreaded rewrite progress

Pretty difficult, high risk of messy code.

There is only one real hurdle, getting stdout and stderr printing to be synchronized and backwards compatible.

This is non-trivial when internals can run threaded, eagerly printing cannot happen, messages have
to be passed back through buffers. Even that would be non-trivial if there wasn't color-term writing happening
making things complicated.

## Rustc termcolor vendoring

A big problem is the way that `rustc` vendors termcolor. It vendors some types but no printing facilities,
and the vendored code isn't interoperable with the published `termcolor` library, which means that
either the printing facilities need to be reinvented (no), or some compatibility-code needs to be introduced (yes).

## Changes

In practice there are four printing facilities used:

1. Regular `stdout`, pretty easy, replace `println` with printing into a buffer.
2. Regular `stderr`, same as above in all ways that matter.
3. Term stdout, this happens in the `diff`-printing part of the code.
4. Term stderr, this is done by `rustc_error` and the most complex to integrate.

Additionally, these four facilities can't be separated, since they have to preserve order between each other.


9 changes: 7 additions & 2 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 295,7 @@ fn format_string(input: String, options: GetOptsOptions) -> Result<i32> {
let printer = Printer::new(config.color());
let mut session = Session::new(config, Some(out), &printer);
format_and_emit_report(&mut session, Input::Text(input));
printer.dump()?;

let exit_code = if session.has_operational_errors() || session.has_parsing_errors() {
1
Expand Down Expand Up @@ -424,7 425,9 @@ fn format(
.unwrap()
.unwrap();
let output = thread_out.session_result?;
stdout().write_all(&output).unwrap();
if !output.is_empty() {
stdout().write_all(&output).unwrap();
}
thread_out.printer.dump()?;
if thread_out.exit_code != 0 {
exit_code = thread_out.exit_code;
Expand All @@ -440,7 443,9 @@ fn format(
let handle_res = handles.remove(&thread_out.id).unwrap().join();
handle_res.unwrap().unwrap();
let output = thread_out.session_result?;
stdout().write_all(&output).unwrap();
if !output.is_empty() {
stdout().write_all(&output).unwrap();
}
thread_out.printer.dump()?;
if thread_out.exit_code != 0 {
exit_code = thread_out.exit_code;
Expand Down
26 changes: 11 additions & 15 deletions src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 17,7 @@ use crate::parse::session::ParseSess;
use crate::print::Printer;
use crate::utils::{contains_skip, count_newlines};
use crate::visitor::FmtVisitor;
use crate::{buf_eprintln, modules, source_file, ErrorKind, FormatReport, Input, Session};
use crate::{buf_eprintln, modules, source_file, ErrorKind, FormatReport, Input, Session, buf_println};

mod generated;
mod newline_style;
Expand All @@ -40,7 40,10 @@ impl<'b, T: Write 'b> Session<'b, T> {
if self.config.disable_all_formatting() {
// When the input is from stdin, echo back the input.
return match input {
Input::Text(ref buf) => echo_back_stdin(buf),
Input::Text(ref buf) => {
buf_println!(self.printer, "{buf}");
Ok(FormatReport::new())
},
_ => Ok(FormatReport::new()),
};
}
Expand Down Expand Up @@ -91,13 94,6 @@ fn should_skip_module<T: FormatHandler>(
false
}

fn echo_back_stdin(input: &str) -> Result<FormatReport, ErrorKind> {
if let Err(e) = io::stdout().write_all(input.as_bytes()) {
return Err(From::from(e));
}
Ok(FormatReport::new())
}

// Format an entire crate (or subset of the module tree).
fn format_project<T: FormatHandler>(
input: Input,
Expand Down Expand Up @@ -153,20 149,20 @@ fn format_project<T: FormatHandler>(

for (path, module) in files {
if input_is_stdin && contains_skip(module.attrs()) {
return echo_back_stdin(
context
buf_println!(printer, "{}", context
.parse_session
.snippet_provider(module.span)
.entire_snippet(),
);
.entire_snippet());
return Ok(FormatReport::new());
}
should_emit_verbose(input_is_stdin, config, || println!("Formatting {}", path));
should_emit_verbose(input_is_stdin, config, || buf_println!(printer, "Formatting {}", path));
context.format_file(path, &module, is_macro_def)?;
}
timer = timer.done_formatting();

should_emit_verbose(input_is_stdin, config, || {
println!(
buf_println!(
printer,
"Spent {0:.3} secs in the parsing phase, and {1:.3} secs in the formatting phase",
timer.get_parse_time(),
timer.get_format_time(),
Expand Down
46 changes: 44 additions & 2 deletions src/print.rs
Original file line number Diff line number Diff line change
@@ -1,3 1,4 @@
use std::fmt::Formatter;
use crate::Color;
use rustc_errors::{Color as RustColor, ColorSpec, WriteColor};
use std::io::{stderr, stdout, Write};
Expand All @@ -22,10 23,18 @@ impl Write for Printer {
Ok(buf.len())
}

#[inline]
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
self.write(buf)?;
Ok(())
}

#[inline]
fn flush(&mut self) -> std::io::Result<()> {
//println!("Flush");
Ok(())
}

}

impl WriteColor for Printer {
Expand All @@ -45,6 54,7 @@ impl WriteColor for Printer {
self.inner.lock().unwrap().current_color.take();
Ok(())
}

}

struct PrinterInner {
Expand Down Expand Up @@ -77,6 87,10 @@ impl Printer {

pub fn dump(&self) -> Result<(), std::io::Error> {
let inner = self.inner.lock().unwrap();
// Pretty common case, early exit
if inner.messages.is_empty() {
return Ok(());
}
let mut use_term_stdout =
term::stdout().filter(|t| inner.color_setting.use_colored_tty() && t.supports_color());
let use_rustc_error_color = inner.color_setting.use_colored_tty()
Expand Down Expand Up @@ -121,6 135,8 @@ impl Printer {
}
}
}
stdout().flush()?;
stderr().flush()?;

Ok(())
}
Expand All @@ -130,8 146,15 @@ impl Printer {
// as far as I can tell
fn rustc_colorspec_compat(rustc: &ColorSpec) -> termcolor::ColorSpec {
let mut cs = termcolor::ColorSpec::new();
let col = rustc.fg().and_then(rustc_color_compat);
cs.set_fg(col);
let fg = rustc.fg().and_then(rustc_color_compat);
cs.set_fg(fg);
let bg = rustc.bg().and_then(rustc_color_compat);
cs.set_bg(bg);
cs.set_bold(rustc.bold());
cs.set_strikethrough(rustc.strikethrough());
cs.set_underline(rustc.underline());
cs.set_intense(rustc.intense());
cs.set_italic(rustc.italic());
cs
}

Expand Down Expand Up @@ -188,6 211,25 @@ pub enum PrintMessage {
RustcErrTerm(RustcErrTermMessage),
}

impl std::fmt::Debug for PrintMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
PrintMessage::Stdout(buf) => {
f.write_fmt(format_args!("PrintMessage::Stdout({:?})", core::str::from_utf8(buf)))
}
PrintMessage::StdErr(buf) => {
f.write_fmt(format_args!("PrintMessage::Stderr({:?})", core::str::from_utf8(buf)))
}
PrintMessage::Term(msg) => {
f.write_fmt(format_args!("PrintMessage::Term({:?}, {:?})", core::str::from_utf8(&msg.message), msg.color))
}
PrintMessage::RustcErrTerm(msg) => {
f.write_fmt(format_args!("PrintMessage::RustcErrTerm({:?}, {:?})", core::str::from_utf8(&msg.message), msg.color))
}
}
}
}

pub struct TermMessage {
message: Vec<u8>,
color: Option<term::color::Color>,
Expand Down