better output noise level control

fuck_this_bullshit
Avril 3 years ago
parent 58fe129bdd
commit c0a608e5d5
Signed by: flanchan
GPG Key ID: 284488987C31F630

1
Cargo.lock generated

@ -123,6 +123,7 @@ dependencies = [
"futures",
"lazy_static",
"num_cpus",
"once_cell",
"pin-project",
"serde",
"serde_cbor",

@ -24,6 +24,7 @@ color-eyre = {version = "0.5.10", default-features=false}
futures = "0.3.12"
lazy_static = "1.4.0"
num_cpus = "1.13.0"
once_cell = "1.5.2"
pin-project = "1.0.5"
serde = {version = "1.0.123", features=["derive"], optional=true}
serde_cbor = {version = "0.11.1", optional=true}

@ -39,6 +39,8 @@ OPTIONS:
-M Set number of parallel running tasks to unlimited. (Same as `--threads 0`). (default).
-m Limit number of parallel tasks to the number of active CPU processors.
-q Quiet mode. Don't output info messages about successful `stat`ing.
-Q Silent mode. Don't output any messages.
-v Verbose mode. Output extra information.
--save <file> Dump the collected data to this file for further inspection (only available when compiled with feature `inspect`)
-D Dump the collected data to `stdout` (see `--save`) (only available when compiled with feature `inspect`)
- Stop parsing arguments, treat all the rest as paths.
@ -104,7 +106,13 @@ fn parse<I: IntoIterator<Item=String>>(args: I) -> eyre::Result<Mode>
cfg.max_tasks = config::max_tasks_cpus();
},
"-q" => {
cfg.silent = true;
cfg.output_level = config::OutputLevel::Quiet;
},
"-Q" => {
cfg.output_level = config::OutputLevel::Silent;
},
"-v" => {
cfg.output_level = config::OutputLevel::Verbose;
},
#[cfg(feature="inspect")] "-D" => {
cfg.serialise_output = Some(None);

@ -1,6 +1,57 @@
use std::path::PathBuf;
use std::num::NonZeroUsize;
use std::{fmt,error};
use once_cell::sync::OnceCell;
static GLOBAL: OnceCell<Config> = OnceCell::new();
/// Get the global config instance, if it has been set.
#[inline] pub fn try_get_global() -> Option<&'static Config>
{
GLOBAL.get()
}
/// Get the global config instance.
/// # Panics
/// If one has not been set yet.
pub fn get_global() -> &'static Config
{
try_get_global().expect("Tried to access global config when it had not been initialised")
}
/// Try to set the global config instance, if it hasn't been already.
#[inline] pub fn try_set_global(cfg: Config) -> Result<(), Config>
{
GLOBAL.set(cfg)
}
/// Set the global config instance.
/// # Panics
/// If one has already been set.
pub fn set_global(cfg: Config)
{
try_set_global(cfg).expect("Tried to set global config more than once")
}
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord)]
#[repr(u32)]
pub enum OutputLevel
{
Silent = 0,
Quiet = 1,
Noisy = 2,
Verbose = 3,
}
impl Default for OutputLevel
{
#[inline]
fn default() -> Self
{
Self::Noisy
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Recursion
@ -54,7 +105,7 @@ pub struct Config
pub recursive: Recursion,
pub max_tasks: Option<NonZeroUsize>,
pub silent: bool,
pub output_level: OutputLevel,
#[cfg(feature="inspect")]
pub serialise_output: Option<Option<PathBuf>>, // Some(None) means dump to `stdout`
@ -62,6 +113,20 @@ pub struct Config
impl Config
{
/// Try to make this the global config instance, if one does not already exist.
#[inline] pub fn try_make_global(self) -> Result<&'static Self, Self>
{
try_set_global(self).map(|_| get_global())
}
/// Make this the global config instance.
/// # Panics
/// If a global config instance has already been set.
#[inline] pub fn make_global(self) -> &'static Self
{
set_global(self);
get_global()
//GLOBAL.get_or_init(move || self) // This isn't okay to do here. As it would silently fail if there was already an instance, when we want it to panic in that case.
}
/// Are we expected to dump data to `stdout`?
#[inline] pub fn is_using_stdout(&self) -> bool
{
@ -96,7 +161,7 @@ impl Default for Config
paths: Vec::new(),
recursive: Default::default(),
max_tasks: None, //max_tasks_cpus(),
silent: false,
output_level: Default::default(),
#[cfg(feature="inspect")]
serialise_output: None,
}
@ -149,11 +214,19 @@ impl fmt::Display for InvalidConfigError
}
}
/// Print an error line in accordance with `Config`'s output directives.
#[macro_export] macro_rules! cfg_eprintln {
($cfg:expr, $fmt:literal $($tt:tt)*) => {
{
if !$cfg.silent {
if $cfg.output_level > $crate::config::OutputLevel::Silent {
eprintln!($fmt $($tt)*);
}
}
};
($level:ident; $cfg:expr, $fmt:literal $($tt:tt)*) => {
{
if $cfg.output_level >= $crate::config::OutputLevel::$level {
eprintln!($fmt $($tt)*);
}
}
@ -165,7 +238,7 @@ impl fmt::Display for InvalidConfigError
($cfg:expr, $fmt:literal $($tt:tt)*) => {
{
let cfg = &$cfg;
if !cfg.silent {
if cfg.output_level > $crate::config::OutputLevel::Quiet {
if cfg.is_using_stdout() {
eprintln!($fmt $($tt)*);
} else {
@ -173,5 +246,18 @@ impl fmt::Display for InvalidConfigError
}
}
}
}
};
($level:ident; $cfg:expr, $fmt:literal $($tt:tt)*) => {
{
let cfg = &$cfg;
if cfg.output_level >= $crate::config::OutputLevel::$level {
if cfg.is_using_stdout() {
eprintln!($fmt $($tt)*);
} else {
println!($fmt $($tt)*);
}
}
}
};
}

@ -1,4 +1,5 @@
//! Mechanism to defer dropping of large objects to background threads
use super::*;
use futures::{
prelude::*,
future::OptionFuture,
@ -16,7 +17,7 @@ where T: Send + 'static
{
let len_bytes = vec.len() * std::mem::size_of::<T>();
OptionFuture::from(if len_bytes > DEFER_DROP_VEC_SIZE_FLOOR {
eprintln!("Size of vector ({} bytes, {} elements of {:?}) exceeds defer drop size floor {}. Moving vector to a seperate thread for de-allocation", len_bytes, vec.len(), std::any::type_name::<T>(), DEFER_DROP_VEC_SIZE_FLOOR);
cfg_eprintln!(Verbose; config::get_global(), "Size of vector ({} bytes, {} elements of {:?}) exceeds defer drop size floor {}. Moving vector to a seperate thread for de-allocation", len_bytes, vec.len(), std::any::type_name::<T>(), DEFER_DROP_VEC_SIZE_FLOOR);
Some(async move {
tokio::task::spawn_blocking(move || drop(vec)).await.expect("Child panic while dropping vector");
})
@ -33,7 +34,7 @@ where T: Send + 'static
{
let len_bytes = vec.len() * std::mem::size_of::<T>();
if len_bytes > DEFER_DROP_VEC_SIZE_FLOOR {
eprintln!("Size of vector ({} bytes, {} elements of {:?}) exceeds defer drop size floor {}. Moving vector to a seperate thread for de-allocation", len_bytes, vec.len(), std::any::type_name::<T>(), DEFER_DROP_VEC_SIZE_FLOOR);
cfg_eprintln!(Verbose; config::get_global(), "Size of vector ({} bytes, {} elements of {:?}) exceeds defer drop size floor {}. Moving vector to a seperate thread for de-allocation", len_bytes, vec.len(), std::any::type_name::<T>(), DEFER_DROP_VEC_SIZE_FLOOR);
tokio::task::spawn_blocking(move || drop(vec));
}
}

@ -42,23 +42,22 @@ async fn normal(cfg: config::Config) -> eyre::Result<()>
return Err(eyre!("Interrupt signalled, exiting"));
}
};
let cfg = cfg.make_global();
let graph = tokio::task::spawn_blocking(move || {
cfg_println!(Verbose; cfg, "Computing hierarchy...");
let mut graph = graph.into_hierarchical();
cfg_println!(Verbose; cfg, "Computing sizes...");
graph.compute_recursive_sizes();
graph
}).await.expect("Failed to compute hierarchy from graph");
#[cfg(debug_assertions)] eprintln!("{:?}", graph);
#[cfg(debug_assertions)] cfg_eprintln!(Verbose; cfg, "{:?}", graph);
if cfg.is_using_stdout() {
eprintln!("Max size file: {:?}", graph.path_max_size_for(data::FsKind::File));
eprintln!("Max size dir: {:?}", graph.path_max_size_for(data::FsKind::Directory));
eprintln!("Max size all: {:?}", graph.path_max_size());
} else {
println!("Max size file: {:?}", graph.path_max_size_for(data::FsKind::File));
println!("Max size dir: {:?}", graph.path_max_size_for(data::FsKind::Directory));
println!("Max size all: {:?}", graph.path_max_size());
}
cfg_println!(Quiet; cfg, "Max size file: {:?}", graph.path_max_size_for(data::FsKind::File));
cfg_println!(Quiet; cfg, "Max size dir: {:?}", graph.path_max_size_for(data::FsKind::Directory));
cfg_println!(Quiet; cfg, "Max size all: {:?}", graph.path_max_size());
#[cfg(feature="inspect")]
match cfg.serialise_output.as_ref().map(|ser_out| {

@ -27,7 +27,7 @@ where W: AsyncWrite + Unpin
{
let mut stream = Compressor::new(&mut to);
eprintln!("Writing {} bytes of type {:?} to stream of type {:?}", vec.len(), std::any::type_name::<T>(), std::any::type_name::<W>());
cfg_eprintln!(Verbose; config::get_global(), "Writing {} bytes of type {:?} to stream of type {:?}", vec.len(), std::any::type_name::<T>(), std::any::type_name::<W>());
stream.write_all(&vec[..])
.await

@ -47,7 +47,7 @@ pub async fn work_on_all(state: State) -> (INodeInfoGraph, Config)
.ok()
},
Err(err) => {
eprintln!("Failed to stat root {:?}: {}", path, err);
cfg_eprintln!(state.config(), "Failed to stat root {:?}: {}", path, err);
None
},
}
@ -117,15 +117,15 @@ fn walk(state: State, root: PathBuf, root_ino: INode) -> BoxFuture<'static, Hash
let mut cache = state.cache_sub();
cache.insert(ino, fsinfo).await;
},
Err(err) => eprintln!("Failed to stat {:?}: {}", entry.path(), err),
Err(err) => cfg_eprintln!(state.config(), "Failed to stat {:?}: {}", entry.path(), err),
}
}
},
Err(err) => eprintln!("Walking {:?} failed: {}", root, err),
Err(err) => cfg_eprintln!(state.config(), "Walking {:?} failed: {}", root, err),
}
}
},
Err(err) => eprintln!("Failed to walk {:?}: {}", root, err),
Err(err) => cfg_eprintln!(state.config(), "Failed to walk {:?}: {}", root, err),
}
// drop work guard here
}
@ -136,7 +136,7 @@ fn walk(state: State, root: PathBuf, root_ino: INode) -> BoxFuture<'static, Hash
{
output.extend(map);
} else {
eprintln!("Child panic");
cfg_eprintln!(state.config(), "Child panic");
}
}

Loading…
Cancel
Save