From 20902e87b97091bf7d524cdec42a87bd8e145d74 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Sat, 15 Apr 2023 00:15:36 -0400 Subject: [PATCH] other: Speed up first draw and first data collection (#1100) * other: add first draw immediately after initialization Previously, I would only do the first draw after an event triggered, so this just makes it so that I *always* draw once first. Some widgets look a bit weird with no data, but this is fine I guess if we want to gain a bit of responsiveness. * other: potentially shorten first time to get data * other: move event loop thread init earlier in app initialization --- CHANGELOG.md | 4 +++- src/app/data_harvester.rs | 15 ++++++++++++++- src/app/layout_manager.rs | 2 +- src/bin/main.rs | 38 +++++++++++++++++++++----------------- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8a7dc926..0d63dbed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1016](https://github.com/ClementTsang/bottom/pull/1016): Add support for displaying process usernames on Windows. - [#1022](https://github.com/ClementTsang/bottom/pull/1022): Support three-character hex colour strings for styling. - [#1024](https://github.com/ClementTsang/bottom/pull/1024): Support FreeBSD temperature sensors based on `hw.temperature`. -- [#1063](https://github.com/ClementTsang/bottom/pull/1063): Add buffer and cache memory tracking +- [#1063](https://github.com/ClementTsang/bottom/pull/1063): Add buffer and cache memory tracking. ## Changes @@ -35,6 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Other +- [#1100](https://github.com/ClementTsang/bottom/pull/1100): Speed up first draw and first data collection. + ## [0.8.0] - 2023-01-22 ## Bug Fixes diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index 67ff1e5bc..362b7251e 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -194,7 +194,20 @@ impl DataCollector { self.update_data(); - std::thread::sleep(std::time::Duration::from_millis(250)); + // Sleep a few seconds to avoid potentially weird data... + let sleep_duration = { + cfg_if::cfg_if! { + if #[cfg(target_os = "freebsd")] { + // FreeBSD's min duration value is 1s, which is a bit too long for me so I'll accept the one-time + // inaccuracy. + std::time::Duration::from_millis(250) + } else { + sysinfo::System::MINIMUM_CPU_UPDATE_INTERVAL + Duration::from_millis(1) + } + } + }; + + std::thread::sleep(sleep_duration); self.data.cleanup(); } diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index 032ccf98c..137a9b124 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -993,7 +993,7 @@ Supported widget names: } } -#[derive(Clone, Default, Debug)] +#[derive(Clone, Default, Debug, Copy)] pub struct UsedWidgets { pub use_cpu: bool, pub use_mem: bool, diff --git a/src/bin/main.rs b/src/bin/main.rs index b05965323..3ffaf2349 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -42,7 +42,7 @@ fn main() -> Result<()> { // let _profiler = dhat::Profiler::new_heap(); let matches = clap::get_matches(); - #[cfg(all(feature = "fern", debug_assertions))] + #[cfg(all(feature = "fern"))] { utils::logging::init_logger(log::LevelFilter::Debug, std::ffi::OsStr::new("debug.log"))?; } @@ -85,15 +85,28 @@ fn main() -> Result<()> { let thread_termination_lock = Arc::new(Mutex::new(false)); let thread_termination_cvar = Arc::new(Condvar::new()); - // Set up input handling let (sender, receiver) = mpsc::channel(); + + // Set up event loop thread; we set this up early to speed up first-time-to-data. + let (collection_thread_ctrl_sender, collection_thread_ctrl_receiver) = mpsc::channel(); + let _collection_thread = create_collection_thread( + sender.clone(), + collection_thread_ctrl_receiver, + thread_termination_lock.clone(), + thread_termination_cvar.clone(), + &app.app_config_fields, + app.filters.clone(), + app.used_widgets, + ); + + // Set up input handling loop thread. let _input_thread = create_input_thread(sender.clone(), thread_termination_lock.clone()); - // Cleaning loop + // Set up cleaning loop thread. let _cleaning_thread = { let lock = thread_termination_lock.clone(); let cvar = thread_termination_cvar.clone(); - let cleaning_sender = sender.clone(); + let cleaning_sender = sender; let offset_wait_time = app.app_config_fields.retention_ms + 60000; thread::spawn(move || { loop { @@ -114,19 +127,7 @@ fn main() -> Result<()> { }) }; - // Event loop - let (collection_thread_ctrl_sender, collection_thread_ctrl_receiver) = mpsc::channel(); - let _collection_thread = create_collection_thread( - sender, - collection_thread_ctrl_receiver, - thread_termination_lock.clone(), - thread_termination_cvar.clone(), - &app.app_config_fields, - app.filters.clone(), - app.used_widgets.clone(), - ); - - // Set up up tui and crossterm + // Set up tui and crossterm let mut stdout_val = stdout(); execute!( stdout_val, @@ -162,6 +163,9 @@ fn main() -> Result<()> { })?; let mut first_run = true; + // Draw once first to initialize the canvas, so it doesn't feel like it's frozen. + try_drawing(&mut terminal, &mut app, &mut painter)?; + while !is_terminated.load(Ordering::SeqCst) { // TODO: Would be good to instead use a mix of is_terminated check + recv. Probably use a termination event instead. if let Ok(recv) = receiver.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {