mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-09-25 18:49:06 +02:00
other: skip the initial sleep on data collection initialization (#1779)
* deps: bump sysinfo * remove sleep on startup * missing collection set * some logic around updating the battery list to match how it is now * more refactoring * oops * forgot to initialize battery manager * fix list updating logic + battery manager logic * comment * initialize should refresh list to true * ah * this works a bit nicer
This commit is contained in:
parent
868667add8
commit
0f212183fe
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1510,9 +1510,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.36.1"
|
version = "0.37.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
|
checksum = "07cec4dc2d2e357ca1e610cfb07de2fa7a10fc3e9fe89f72545f3d244ea87753"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -96,7 +96,7 @@ nvml-wrapper = { version = "0.11.0", optional = true, features = [
|
|||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
starship-battery = { version = "0.10.2", optional = true }
|
starship-battery = { version = "0.10.2", optional = true }
|
||||||
sysinfo = "=0.36.1"
|
sysinfo = "=0.37.0"
|
||||||
timeless = "0.0.14-alpha"
|
timeless = "0.0.14-alpha"
|
||||||
toml_edit = { version = "0.22.27", features = ["serde"] }
|
toml_edit = { version = "0.22.27", features = ["serde"] }
|
||||||
tui = { version = "0.29.0", package = "ratatui", features = [
|
tui = { version = "0.29.0", package = "ratatui", features = [
|
||||||
|
@ -150,15 +150,22 @@ impl Default for SysinfoSource {
|
|||||||
pub struct DataCollector {
|
pub struct DataCollector {
|
||||||
pub data: Data,
|
pub data: Data,
|
||||||
sys: SysinfoSource,
|
sys: SysinfoSource,
|
||||||
use_current_cpu_total: bool,
|
|
||||||
unnormalized_cpu: bool,
|
|
||||||
last_collection_time: Instant,
|
last_collection_time: Instant,
|
||||||
total_rx: u64,
|
|
||||||
total_tx: u64,
|
|
||||||
show_average_cpu: bool,
|
|
||||||
widgets_to_harvest: UsedWidgets,
|
widgets_to_harvest: UsedWidgets,
|
||||||
filters: DataFilters,
|
filters: DataFilters,
|
||||||
|
|
||||||
|
total_rx: u64,
|
||||||
|
total_tx: u64,
|
||||||
|
|
||||||
|
unnormalized_cpu: bool,
|
||||||
|
use_current_cpu_total: bool,
|
||||||
|
show_average_cpu: bool,
|
||||||
|
|
||||||
|
#[cfg(any(not(target_os = "linux"), feature = "battery"))]
|
||||||
|
last_list_collection_time: Instant,
|
||||||
|
#[cfg(any(not(target_os = "linux"), feature = "battery"))]
|
||||||
|
should_refresh_list: bool,
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pid_mapping: HashMap<Pid, processes::PrevProcDetails>,
|
pid_mapping: HashMap<Pid, processes::PrevProcDetails>,
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@ -180,11 +187,13 @@ pub struct DataCollector {
|
|||||||
gpus_total_mem: Option<u64>,
|
gpus_total_mem: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LIST_REFRESH_TIME: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
impl DataCollector {
|
impl DataCollector {
|
||||||
pub fn new(filters: DataFilters) -> Self {
|
pub fn new(filters: DataFilters) -> Self {
|
||||||
// Initialize it to the past to force it to load on initialization.
|
// Initialize it to the past to force it to load on initialization.
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let last_collection_time = now.checked_sub(Duration::from_secs(600)).unwrap_or(now);
|
let last_collection_time = now.checked_sub(LIST_REFRESH_TIME * 10).unwrap_or(now);
|
||||||
|
|
||||||
DataCollector {
|
DataCollector {
|
||||||
data: Data::default(),
|
data: Data::default(),
|
||||||
@ -213,32 +222,32 @@ impl DataCollector {
|
|||||||
gpu_pids: None,
|
gpu_pids: None,
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
gpus_total_mem: None,
|
gpus_total_mem: None,
|
||||||
|
#[cfg(any(not(target_os = "linux"), feature = "battery"))]
|
||||||
|
last_list_collection_time: last_collection_time,
|
||||||
|
#[cfg(any(not(target_os = "linux"), feature = "battery"))]
|
||||||
|
should_refresh_list: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&mut self) {
|
/// Update the check for updating things like lists of batteries, etc.
|
||||||
#[cfg(feature = "battery")]
|
/// This is useful for things that we don't want to update all the time.
|
||||||
|
///
|
||||||
|
/// Note this should be set back to false if `self.last_list_collection_time` is updated.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(not(target_os = "linux"), feature = "battery"))]
|
||||||
|
fn update_refresh_list_check(&mut self) {
|
||||||
|
if self
|
||||||
|
.data
|
||||||
|
.collection_time
|
||||||
|
.duration_since(self.last_list_collection_time)
|
||||||
|
> LIST_REFRESH_TIME
|
||||||
{
|
{
|
||||||
if self.widgets_to_harvest.use_battery {
|
self.should_refresh_list = true;
|
||||||
if let Ok(battery_manager) = Manager::new() {
|
|
||||||
if let Ok(batteries) = battery_manager.batteries() {
|
|
||||||
let battery_list: Vec<Battery> = batteries.filter_map(Result::ok).collect();
|
|
||||||
if !battery_list.is_empty() {
|
|
||||||
self.battery_list = Some(battery_list);
|
|
||||||
self.battery_manager = Some(battery_manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_data();
|
if self.should_refresh_list {
|
||||||
|
self.last_list_collection_time = self.data.collection_time;
|
||||||
// Sleep a few seconds to avoid potentially weird data.
|
}
|
||||||
const SLEEP: Duration = get_sleep_duration();
|
|
||||||
|
|
||||||
std::thread::sleep(SLEEP);
|
|
||||||
self.data.cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_collection(&mut self, used_widgets: UsedWidgets) {
|
pub fn set_collection(&mut self, used_widgets: UsedWidgets) {
|
||||||
@ -286,9 +295,6 @@ impl DataCollector {
|
|||||||
// - Temperatures and temperature components list.
|
// - Temperatures and temperature components list.
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
const LIST_REFRESH_TIME: Duration = Duration::from_secs(60);
|
|
||||||
let refresh_start = Instant::now();
|
|
||||||
|
|
||||||
if self.widgets_to_harvest.use_proc {
|
if self.widgets_to_harvest.use_proc {
|
||||||
self.sys.system.refresh_processes_specifics(
|
self.sys.system.refresh_processes_specifics(
|
||||||
sysinfo::ProcessesToUpdate::All,
|
sysinfo::ProcessesToUpdate::All,
|
||||||
@ -301,13 +307,13 @@ impl DataCollector {
|
|||||||
|
|
||||||
// For Windows, sysinfo also handles the users list.
|
// For Windows, sysinfo also handles the users list.
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
if refresh_start.duration_since(self.last_collection_time) > LIST_REFRESH_TIME {
|
if self.should_refresh_list {
|
||||||
self.sys.users.refresh();
|
self.sys.users.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.widgets_to_harvest.use_temp {
|
if self.widgets_to_harvest.use_temp {
|
||||||
if refresh_start.duration_since(self.last_collection_time) > LIST_REFRESH_TIME {
|
if self.should_refresh_list {
|
||||||
self.sys.temps.refresh(true);
|
self.sys.temps.refresh(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +324,7 @@ impl DataCollector {
|
|||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
if self.widgets_to_harvest.use_disk {
|
if self.widgets_to_harvest.use_disk {
|
||||||
if refresh_start.duration_since(self.last_collection_time) > LIST_REFRESH_TIME {
|
if self.should_refresh_list {
|
||||||
self.sys.disks.refresh(true);
|
self.sys.disks.refresh(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,10 +336,15 @@ impl DataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_data(&mut self) {
|
pub fn update_data(&mut self) {
|
||||||
self.refresh_sysinfo_data();
|
|
||||||
|
|
||||||
self.data.collection_time = Instant::now();
|
self.data.collection_time = Instant::now();
|
||||||
|
|
||||||
|
#[cfg(any(not(target_os = "linux"), feature = "battery"))]
|
||||||
|
{
|
||||||
|
self.update_refresh_list_check();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.refresh_sysinfo_data();
|
||||||
|
|
||||||
self.update_cpu_usage();
|
self.update_cpu_usage();
|
||||||
self.update_memory_usage();
|
self.update_memory_usage();
|
||||||
self.update_temps();
|
self.update_temps();
|
||||||
@ -342,16 +353,23 @@ impl DataCollector {
|
|||||||
self.update_batteries();
|
self.update_batteries();
|
||||||
|
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
self.update_gpus(); // update_gpus before procs for gpu_pids but after temps for appending
|
self.update_gpus();
|
||||||
|
|
||||||
self.update_processes();
|
self.update_processes();
|
||||||
self.update_network_usage();
|
self.update_network_usage();
|
||||||
self.update_disks();
|
self.update_disks();
|
||||||
|
|
||||||
|
#[cfg(any(not(target_os = "linux"), feature = "battery"))]
|
||||||
|
{
|
||||||
|
self.should_refresh_list = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Update times for future reference.
|
// Update times for future reference.
|
||||||
self.last_collection_time = self.data.collection_time;
|
self.last_collection_time = self.data.collection_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets GPU data. Note this will usually append to other previously
|
||||||
|
/// collected data fields at the moment.
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_gpus(&mut self) {
|
fn update_gpus(&mut self) {
|
||||||
@ -462,15 +480,13 @@ impl DataCollector {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_network_usage(&mut self) {
|
fn update_network_usage(&mut self) {
|
||||||
let current_instant = self.data.collection_time;
|
|
||||||
|
|
||||||
if self.widgets_to_harvest.use_net {
|
if self.widgets_to_harvest.use_net {
|
||||||
let net_data = network::get_network_data(
|
let net_data = network::get_network_data(
|
||||||
&self.sys.network,
|
&self.sys.network,
|
||||||
self.last_collection_time,
|
self.last_collection_time,
|
||||||
&mut self.total_rx,
|
&mut self.total_rx,
|
||||||
&mut self.total_tx,
|
&mut self.total_tx,
|
||||||
current_instant,
|
self.data.collection_time,
|
||||||
&self.filters.net_filter,
|
&self.filters.net_filter,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -480,15 +496,59 @@ impl DataCollector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update battery information.
|
||||||
|
///
|
||||||
|
/// If the battery manager is not initialized, it will attempt to initialize it if at least one battery is found.
|
||||||
|
///
|
||||||
|
/// This function also refreshes the list of batteries if `self.should_refresh_list` is true.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "battery")]
|
#[cfg(feature = "battery")]
|
||||||
fn update_batteries(&mut self) {
|
fn update_batteries(&mut self) {
|
||||||
if let Some(battery_manager) = &self.battery_manager {
|
let battery_manager = match &self.battery_manager {
|
||||||
if let Some(battery_list) = &mut self.battery_list {
|
Some(manager) => {
|
||||||
self.data.list_of_batteries =
|
// Also check if we need to refresh the list of batteries.
|
||||||
Some(batteries::refresh_batteries(battery_manager, battery_list));
|
if self.should_refresh_list {
|
||||||
|
let battery_list = manager
|
||||||
|
.batteries()
|
||||||
|
.map(|batteries| batteries.filter_map(Result::ok).collect::<Vec<_>>());
|
||||||
|
|
||||||
|
if let Ok(battery_list) = battery_list {
|
||||||
|
if battery_list.is_empty() {
|
||||||
|
self.battery_list = None;
|
||||||
|
} else {
|
||||||
|
self.battery_list = Some(battery_list);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.battery_list = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
|
if let Ok(manager) = Manager::new() {
|
||||||
|
let Ok(batteries) = manager.batteries() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let battery_list = batteries.filter_map(Result::ok).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if battery_list.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.battery_list = Some(battery_list);
|
||||||
|
self.battery_manager.insert(manager)
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.data.list_of_batteries = self
|
||||||
|
.battery_list
|
||||||
|
.as_mut()
|
||||||
|
.map(|battery_list| batteries::refresh_batteries(battery_manager, battery_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -510,31 +570,6 @@ impl DataCollector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We set a sleep duration between 10ms and 250ms, ideally sysinfo's
|
|
||||||
/// [`sysinfo::MINIMUM_CPU_UPDATE_INTERVAL`] + 1.
|
|
||||||
///
|
|
||||||
/// We bound the upper end to avoid waiting too long (e.g. FreeBSD is 1s, which
|
|
||||||
/// I'm fine with losing accuracy on for the first refresh), and we bound the
|
|
||||||
/// lower end just to avoid the off-chance that refreshing too quickly causes
|
|
||||||
/// problems. This second case should only happen on unsupported systems via
|
|
||||||
/// sysinfo, in which case [`sysinfo::MINIMUM_CPU_UPDATE_INTERVAL`] is defined
|
|
||||||
/// as 0.
|
|
||||||
///
|
|
||||||
/// We also do `INTERVAL + 1` for some wiggle room, just in case.
|
|
||||||
const fn get_sleep_duration() -> Duration {
|
|
||||||
const MIN_SLEEP: u64 = 10;
|
|
||||||
const MAX_SLEEP: u64 = 250;
|
|
||||||
const INTERVAL: u64 = sysinfo::MINIMUM_CPU_UPDATE_INTERVAL.as_millis() as u64;
|
|
||||||
|
|
||||||
if INTERVAL < MIN_SLEEP {
|
|
||||||
Duration::from_millis(MIN_SLEEP)
|
|
||||||
} else if INTERVAL > MAX_SLEEP {
|
|
||||||
Duration::from_millis(MAX_SLEEP)
|
|
||||||
} else {
|
|
||||||
Duration::from_millis(INTERVAL + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
/// Deserialize [libxo](https://www.freebsd.org/cgi/man.cgi?query=libxo&apropos=0&sektion=0&manpath=FreeBSD+13.1-RELEASE+and+Ports&arch=default&format=html) JSON data
|
/// Deserialize [libxo](https://www.freebsd.org/cgi/man.cgi?query=libxo&apropos=0&sektion=0&manpath=FreeBSD+13.1-RELEASE+and+Ports&arch=default&format=html) JSON data
|
||||||
fn deserialize_xo<T>(key: &str, data: &[u8]) -> Result<T, std::io::Error>
|
fn deserialize_xo<T>(key: &str, data: &[u8]) -> Result<T, std::io::Error>
|
||||||
|
@ -219,7 +219,7 @@ fn create_collection_thread(
|
|||||||
let use_current_cpu_total = app_config_fields.use_current_cpu_total;
|
let use_current_cpu_total = app_config_fields.use_current_cpu_total;
|
||||||
let unnormalized_cpu = app_config_fields.unnormalized_cpu;
|
let unnormalized_cpu = app_config_fields.unnormalized_cpu;
|
||||||
let show_average_cpu = app_config_fields.show_average_cpu;
|
let show_average_cpu = app_config_fields.show_average_cpu;
|
||||||
let update_time = app_config_fields.update_rate;
|
let update_sleep = app_config_fields.update_rate;
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut data_state = collection::DataCollector::new(filters);
|
let mut data_state = collection::DataCollector::new(filters);
|
||||||
@ -229,8 +229,6 @@ fn create_collection_thread(
|
|||||||
data_state.set_unnormalized_cpu(unnormalized_cpu);
|
data_state.set_unnormalized_cpu(unnormalized_cpu);
|
||||||
data_state.set_show_average_cpu(show_average_cpu);
|
data_state.set_show_average_cpu(show_average_cpu);
|
||||||
|
|
||||||
data_state.init();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Check once at the very top... don't block though.
|
// Check once at the very top... don't block though.
|
||||||
if let Some(is_terminated) = cancellation_token.try_check() {
|
if let Some(is_terminated) = cancellation_token.try_check() {
|
||||||
@ -264,7 +262,7 @@ fn create_collection_thread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sleep while allowing for interruptions...
|
// Sleep while allowing for interruptions...
|
||||||
if cancellation_token.sleep_with_cancellation(Duration::from_millis(update_time)) {
|
if cancellation_token.sleep_with_cancellation(Duration::from_millis(update_sleep)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -672,7 +672,7 @@ macro_rules! parse_ms_option {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How fast the screen refreshes
|
/// How quickly we update data.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_update_rate(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
|
fn get_update_rate(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
|
||||||
const DEFAULT_REFRESH_RATE_IN_MILLISECONDS: u64 = 1000;
|
const DEFAULT_REFRESH_RATE_IN_MILLISECONDS: u64 = 1000;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user