diff --git a/Cargo.lock b/Cargo.lock index d645957da96af..f41afce6ca525 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1979,9 +1979,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" dependencies = [ "console", "instant", @@ -4467,6 +4467,7 @@ version = "0.0.0" dependencies = [ "bitflags 2.4.1", "getopts", + "indicatif", "libc", "rustc_ast", "rustc_data_structures", diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index a827717d9bbd1..cc8603080ae39 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -29,6 +29,7 @@ use rustc_query_system::{LayoutOfDepth, QueryOverflow}; use rustc_serialize::Decodable; use rustc_serialize::Encodable; use rustc_session::Limit; +use rustc_session::ProgressBars; use rustc_span::def_id::LOCAL_CRATE; use std::num::NonZeroU64; use thin_vec::ThinVec; @@ -420,6 +421,24 @@ where value } +macro_rules! trace_query { + ($tcx:expr, $name:ident, $key:ident) => { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?$key).entered(); + let _spinner = $tcx + .sess + .progress_bars + .as_ref() + .map(|bars| $crate::plumbing::update_spinner($tcx, bars, stringify!($name))); + }; +} + +#[inline(never)] +#[cold] +pub fn update_spinner(tcx: TyCtxt<'_>, bars: &ProgressBars, name: &'static str) -> impl Sized { + tcx.sess.push_spinner(bars, name) +} + fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool where Q: QueryConfig>, @@ -538,8 +557,7 @@ macro_rules! define_queries { key: queries::$name::Key<'tcx>, mode: QueryMode, ) -> Option>> { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + trace_query!(tcx, $name, key); get_query_incr( QueryType::config(tcx), QueryCtxt::new(tcx), @@ -580,8 +598,7 @@ macro_rules! define_queries { cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), execute_query: |tcx, key| erase(tcx.$name(key)), compute: |tcx, key| { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + trace_query!(tcx, $name, key); __rust_begin_short_backtrace(|| queries::$name::provided_to_erased( tcx, diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index ba8f67982f51a..f40cdf140ff0b 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start bitflags = "2.4.1" getopts = "0.2" +indicatif = "0.17.7" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 0d6328fbb071c..a8865a69aedb1 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -26,6 +26,8 @@ pub mod config; pub mod cstore; pub mod filesearch; mod options; +mod progress; +pub use progress::*; pub mod search_paths; mod session; diff --git a/compiler/rustc_session/src/progress.rs b/compiler/rustc_session/src/progress.rs new file mode 100644 index 0000000000000..9e2e0134b39a8 --- /dev/null +++ b/compiler/rustc_session/src/progress.rs @@ -0,0 +1,88 @@ +use std::{ + cell::RefCell, + sync::mpsc::{Sender, TryRecvError}, + thread::ThreadId, + time::Duration, +}; + +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use rustc_data_structures::{fx::FxHashMap, sync::IntoDynSyncSend}; + +use crate::Session; + +thread_local! { + static CURRENT_SPINNER: RefCell> = RefCell::new(None); +} + +pub struct ProgressBars { + sender: IntoDynSyncSend>, +} + +enum Msg { + Pop { thread: ThreadId }, + Push { thread: ThreadId, name: &'static str }, +} + +impl Session { + /// Starts up a thread that makes sure all the threads' messages are collected and processed + /// in one central location, and thus rendered correctly. + pub(crate) fn init_progress_bars() -> ProgressBars { + let (sender, receiver) = std::sync::mpsc::channel(); + std::thread::spawn(move || { + let bars = MultiProgress::new(); + let mut threads: FxHashMap> = FxHashMap::default(); + 'outer: loop { + std::thread::sleep(Duration::from_millis(100)); + loop { + match receiver.try_recv() { + Ok(val) => match val { + Msg::Pop { thread } => { + threads.get_mut(&thread).unwrap().pop(); + } + Msg::Push { thread, name } => { + let stack = threads.entry(thread).or_default(); + + let mut template = String::new(); + use std::fmt::Write; + if !stack.is_empty() { + for _ in 1..stack.len() { + write!(template, " ").unwrap(); + } + write!(template, "└").unwrap(); + } + write!(template, "{{spinner}} {{msg}}").unwrap(); + + let spinner = ProgressBar::new_spinner() + .with_message(name) + .with_style(ProgressStyle::with_template(&template).unwrap()); + let spinner = bars.add(spinner); + stack.push(spinner) + } + }, + Err(TryRecvError::Disconnected) => break 'outer, + Err(TryRecvError::Empty) => break, + } + } + for thread in threads.values() { + for spinner in thread { + spinner.tick() + } + } + } + }); + ProgressBars { sender: IntoDynSyncSend(sender) } + } + + /// Append a new spinner to the current stack + pub fn push_spinner(&self, bars: &ProgressBars, name: &'static str) -> impl Sized { + let thread = std::thread::current().id(); + bars.sender.send(Msg::Push { thread, name }).unwrap(); + struct Spinner(Sender, ThreadId); + impl Drop for Spinner { + fn drop(&mut self) { + self.0.send(Msg::Pop { thread: self.1 }).unwrap(); + } + } + Spinner(bars.sender.0.clone(), thread) + } +} diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 7cd76ad729388..87ec3ab003223 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -7,6 +7,7 @@ use crate::config::{ use crate::config::{ErrorOutputType, Input}; use crate::errors; use crate::parse::{add_feature_diagnostics, ParseSess}; +use crate::progress::ProgressBars; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; @@ -158,6 +159,10 @@ pub struct Session { /// Data about code being compiled, gathered during compilation. pub code_stats: CodeStats, + /// The central object where progress information should be displayed in. + /// Is `Some` if `RUSTC_PROGRESS` is set. + pub progress_bars: Option, + /// Tracks fuel info if `-zfuel=crate=n` is specified. optimization_fuel: Lock, @@ -1155,6 +1160,11 @@ pub fn build_session( let asm_arch = if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None }; + let progress_bars = match std::env::var_os("RUSTC_PROGRESS") { + Some(val) if val != "0" => Some(Session::init_progress_bars()), + _ => None, + }; + let sess = Session { target: target_cfg, host, @@ -1167,6 +1177,7 @@ pub fn build_session( incr_comp_session: RwLock::new(IncrCompSession::NotInitialized), prof, code_stats: Default::default(), + progress_bars, optimization_fuel, print_fuel, jobserver: jobserver::client(), diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b06c072a2b0fd..31b189af71224 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -204,6 +204,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "cc", "cfg-if", "compiler_builtins", + "console", // Dependency of indicatif "convert_case", // dependency of derive_more "cpufeatures", "crc32fast", @@ -226,6 +227,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "either", "elsa", "ena", + "encode_unicode", // Dependency of indicatif "equivalent", "errno", "expect-test", @@ -255,6 +257,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "icu_provider_macros", "ident_case", "indexmap", + "indicatif", "intl-memoizer", "intl_pluralrules", "is-terminal", @@ -278,6 +281,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "miniz_oxide", "nu-ansi-term", "num_cpus", + "number_prefix", // Dependency of indicatif "object", "odht", "once_cell", @@ -288,7 +292,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "perf-event-open-sys", "pin-project-lite", "polonius-engine", - "portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std + "portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std, and indicatif "ppv-lite86", "proc-macro-hack", "proc-macro2",