mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-23 21:55:11 +02:00
bug: Fix some performance regressions (#344)
Fixes some performance regressions and forgotten cleanup. Changes to attempt to improve performance to match 0.4.x: - Remove `trace!` and `--debug` for now. These were a significant hog. Removing this dropped initial memory usage by about half. - Add additional cleaning step for `pid_mapping` during process harvesting. This should hopefully improve memory usage as time goes on. - Slightly change how we do sorting to hopefully be a bit more optimal? This was just an easy change to make that I spotted. - Fix broken cleaning child thread task.
This commit is contained in:
parent
030f4ddd6a
commit
fd003f84da
10
.gitignore
vendored
10
.gitignore
vendored
@ -5,13 +5,21 @@
|
|||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
# Stuff to really ignore
|
# Logging
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
# Flamegraph stuff
|
||||||
rust-unmangle
|
rust-unmangle
|
||||||
*.svg
|
*.svg
|
||||||
*.data
|
*.data
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# Heaptrack files
|
||||||
|
*.zst
|
||||||
|
|
||||||
|
# For testing
|
||||||
sample_configs/testing.toml
|
sample_configs/testing.toml
|
||||||
|
|
||||||
# Wix
|
# Wix
|
||||||
|
@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|
||||||
|
- [#344](https://github.com/ClementTsang/bottom/pull/344): Fixes a performance regression causing high memory and CPU usage over time.
|
||||||
|
|
||||||
- [#345](https://github.com/ClementTsang/bottom/pull/345): Fixes process states not showing.
|
- [#345](https://github.com/ClementTsang/bottom/pull/345): Fixes process states not showing.
|
||||||
|
|
||||||
## [0.5.3] - 2020-11-26
|
## [0.5.3] - 2020-11-26
|
||||||
|
@ -19,6 +19,7 @@ doc = false
|
|||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = 1
|
debug = 1
|
||||||
|
# debug = true
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
@ -88,4 +89,4 @@ output = "bottom_x86_64_installer.msi"
|
|||||||
[dev-dependencies.cargo-husky]
|
[dev-dependencies.cargo-husky]
|
||||||
version = "1"
|
version = "1"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["user-hooks"]
|
features = ["user-hooks"]
|
||||||
|
@ -222,7 +222,6 @@ Use `btm --help` for more information.
|
|||||||
--color <COLOR SCHEME> Use a color scheme, use --help for supported values.
|
--color <COLOR SCHEME> Use a color scheme, use --help for supported values.
|
||||||
-C, --config <CONFIG PATH> Sets the location of the config file.
|
-C, --config <CONFIG PATH> Sets the location of the config file.
|
||||||
-u, --current_usage Sets process CPU% to be based on current CPU%.
|
-u, --current_usage Sets process CPU% to be based on current CPU%.
|
||||||
--debug Enables debug logging.
|
|
||||||
-t, --default_time_value <MS> Default time value for graphs in ms.
|
-t, --default_time_value <MS> Default time value for graphs in ms.
|
||||||
--default_widget_count <INT> Sets the n'th selected widget type as the default.
|
--default_widget_count <INT> Sets the n'th selected widget type as the default.
|
||||||
--default_widget_type <WIDGET TYPE> Sets which widget type to use as the default widget.
|
--default_widget_type <WIDGET TYPE> Sets which widget type to use as the default widget.
|
||||||
|
@ -102,26 +102,30 @@ impl DataCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean_data(&mut self, max_time_millis: u64) {
|
pub fn clean_data(&mut self, max_time_millis: u64) {
|
||||||
trace!("Cleaning data.");
|
// trace!("Cleaning data.");
|
||||||
let current_time = Instant::now();
|
let current_time = Instant::now();
|
||||||
|
|
||||||
let mut remove_index = 0;
|
let remove_index = match self
|
||||||
for entry in &self.timed_data_vec {
|
.timed_data_vec
|
||||||
if current_time.duration_since(entry.0).as_millis() >= max_time_millis as u128 {
|
.binary_search_by(|(instant, _timed_data)| {
|
||||||
remove_index += 1;
|
current_time
|
||||||
} else {
|
.duration_since(*instant)
|
||||||
break;
|
.as_millis()
|
||||||
}
|
.cmp(&(max_time_millis as u128))
|
||||||
}
|
.reverse()
|
||||||
|
}) {
|
||||||
|
Ok(index) => index,
|
||||||
|
Err(index) => index,
|
||||||
|
};
|
||||||
|
|
||||||
self.timed_data_vec.drain(0..remove_index);
|
self.timed_data_vec.drain(0..remove_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eat_data(&mut self, harvested_data: &Data) {
|
pub fn eat_data(&mut self, harvested_data: &Data) {
|
||||||
trace!("Eating data now...");
|
// trace!("Eating data now...");
|
||||||
let harvested_time = harvested_data.last_collection_time;
|
let harvested_time = harvested_data.last_collection_time;
|
||||||
trace!("Harvested time: {:?}", harvested_time);
|
// trace!("Harvested time: {:?}", harvested_time);
|
||||||
trace!("New current instant: {:?}", self.current_instant);
|
// trace!("New current instant: {:?}", self.current_instant);
|
||||||
let mut new_entry = TimedData::default();
|
let mut new_entry = TimedData::default();
|
||||||
|
|
||||||
// Network
|
// Network
|
||||||
@ -171,7 +175,7 @@ impl DataCollection {
|
|||||||
fn eat_memory_and_swap(
|
fn eat_memory_and_swap(
|
||||||
&mut self, memory: &mem::MemHarvest, swap: &mem::MemHarvest, new_entry: &mut TimedData,
|
&mut self, memory: &mem::MemHarvest, swap: &mem::MemHarvest, new_entry: &mut TimedData,
|
||||||
) {
|
) {
|
||||||
trace!("Eating mem and swap.");
|
// trace!("Eating mem and swap.");
|
||||||
// Memory
|
// Memory
|
||||||
let mem_percent = match memory.mem_total_in_mb {
|
let mem_percent = match memory.mem_total_in_mb {
|
||||||
0 => 0f64,
|
0 => 0f64,
|
||||||
@ -194,7 +198,7 @@ impl DataCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn eat_network(&mut self, network: &network::NetworkHarvest, new_entry: &mut TimedData) {
|
fn eat_network(&mut self, network: &network::NetworkHarvest, new_entry: &mut TimedData) {
|
||||||
trace!("Eating network.");
|
// trace!("Eating network.");
|
||||||
// FIXME [NETWORKING; CONFIG]: The ability to config this?
|
// FIXME [NETWORKING; CONFIG]: The ability to config this?
|
||||||
// FIXME [NETWORKING]: Support bits, support switching between decimal and binary units (move the log part to conversion and switch on the fly)
|
// FIXME [NETWORKING]: Support bits, support switching between decimal and binary units (move the log part to conversion and switch on the fly)
|
||||||
// RX
|
// RX
|
||||||
@ -216,7 +220,7 @@ impl DataCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn eat_cpu(&mut self, cpu: &[cpu::CpuData], new_entry: &mut TimedData) {
|
fn eat_cpu(&mut self, cpu: &[cpu::CpuData], new_entry: &mut TimedData) {
|
||||||
trace!("Eating CPU.");
|
// trace!("Eating CPU.");
|
||||||
// Note this only pre-calculates the data points - the names will be
|
// Note this only pre-calculates the data points - the names will be
|
||||||
// within the local copy of cpu_harvest. Since it's all sequential
|
// within the local copy of cpu_harvest. Since it's all sequential
|
||||||
// it probably doesn't matter anyways.
|
// it probably doesn't matter anyways.
|
||||||
@ -227,7 +231,7 @@ impl DataCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn eat_temp(&mut self, temperature_sensors: &[temperature::TempHarvest]) {
|
fn eat_temp(&mut self, temperature_sensors: &[temperature::TempHarvest]) {
|
||||||
trace!("Eating temps.");
|
// trace!("Eating temps.");
|
||||||
// TODO: [PO] To implement
|
// TODO: [PO] To implement
|
||||||
self.temp_harvest = temperature_sensors.to_vec();
|
self.temp_harvest = temperature_sensors.to_vec();
|
||||||
}
|
}
|
||||||
@ -235,7 +239,7 @@ impl DataCollection {
|
|||||||
fn eat_disks(
|
fn eat_disks(
|
||||||
&mut self, disks: &[disks::DiskHarvest], io: &disks::IOHarvest, harvested_time: Instant,
|
&mut self, disks: &[disks::DiskHarvest], io: &disks::IOHarvest, harvested_time: Instant,
|
||||||
) {
|
) {
|
||||||
trace!("Eating disks.");
|
// trace!("Eating disks.");
|
||||||
// TODO: [PO] To implement
|
// TODO: [PO] To implement
|
||||||
|
|
||||||
let time_since_last_harvest = harvested_time
|
let time_since_last_harvest = harvested_time
|
||||||
@ -308,12 +312,12 @@ impl DataCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn eat_proc(&mut self, list_of_processes: &[processes::ProcessHarvest]) {
|
fn eat_proc(&mut self, list_of_processes: &[processes::ProcessHarvest]) {
|
||||||
trace!("Eating proc.");
|
// trace!("Eating proc.");
|
||||||
self.process_harvest = list_of_processes.to_vec();
|
self.process_harvest = list_of_processes.to_vec();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eat_battery(&mut self, list_of_batteries: &[batteries::BatteryHarvest]) {
|
fn eat_battery(&mut self, list_of_batteries: &[batteries::BatteryHarvest]) {
|
||||||
trace!("Eating batteries.");
|
// trace!("Eating batteries.");
|
||||||
self.battery_harvest = list_of_batteries.to_vec();
|
self.battery_harvest = list_of_batteries.to_vec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,10 +94,10 @@ pub struct DataCollector {
|
|||||||
|
|
||||||
impl Default for DataCollector {
|
impl Default for DataCollector {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
trace!("Creating default data collector...");
|
// trace!("Creating default data collector...");
|
||||||
DataCollector {
|
DataCollector {
|
||||||
data: Data::default(),
|
data: Data::default(),
|
||||||
sys: System::new_all(),
|
sys: System::new_with_specifics(sysinfo::RefreshKind::new()),
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pid_mapping: HashMap::new(),
|
pid_mapping: HashMap::new(),
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@ -116,9 +116,10 @@ impl Default for DataCollector {
|
|||||||
battery_list: None,
|
battery_list: None,
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
page_file_size_kb: unsafe {
|
page_file_size_kb: unsafe {
|
||||||
let page_file_size_kb = libc::sysconf(libc::_SC_PAGESIZE) as u64 / 1024;
|
// let page_file_size_kb = libc::sysconf(libc::_SC_PAGESIZE) as u64 / 1024;
|
||||||
trace!("Page file size in KB: {}", page_file_size_kb);
|
// trace!("Page file size in KB: {}", page_file_size_kb);
|
||||||
page_file_size_kb
|
// page_file_size_kb
|
||||||
|
libc::sysconf(libc::_SC_PAGESIZE) as u64 / 1024
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,12 +127,13 @@ impl Default for DataCollector {
|
|||||||
|
|
||||||
impl DataCollector {
|
impl DataCollector {
|
||||||
pub fn init(&mut self) {
|
pub fn init(&mut self) {
|
||||||
trace!("Initializing data collector.");
|
// trace!("Initializing data collector.");
|
||||||
|
self.sys.refresh_memory();
|
||||||
self.mem_total_kb = self.sys.get_total_memory();
|
self.mem_total_kb = self.sys.get_total_memory();
|
||||||
trace!("Total memory in KB: {}", self.mem_total_kb);
|
// trace!("Total memory in KB: {}", self.mem_total_kb);
|
||||||
|
|
||||||
if self.widgets_to_harvest.use_battery {
|
if self.widgets_to_harvest.use_battery {
|
||||||
trace!("First run battery vec creation.");
|
// trace!("First run battery vec creation.");
|
||||||
if let Ok(battery_manager) = Manager::new() {
|
if let Ok(battery_manager) = Manager::new() {
|
||||||
if let Ok(batteries) = battery_manager.batteries() {
|
if let Ok(batteries) = battery_manager.batteries() {
|
||||||
let battery_list: Vec<Battery> = batteries.filter_map(Result::ok).collect();
|
let battery_list: Vec<Battery> = batteries.filter_map(Result::ok).collect();
|
||||||
@ -143,15 +145,15 @@ impl DataCollector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Running first run.");
|
// trace!("Running first run.");
|
||||||
futures::executor::block_on(self.update_data());
|
futures::executor::block_on(self.update_data());
|
||||||
trace!("First run done. Sleeping for 250ms...");
|
// trace!("First run done. Sleeping for 250ms...");
|
||||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||||
|
|
||||||
trace!("First run done. Running first run cleanup now.");
|
// trace!("First run done. Running first run cleanup now.");
|
||||||
self.data.cleanup();
|
self.data.cleanup();
|
||||||
|
|
||||||
trace!("Enabled widgets to harvest: {:#?}", self.widgets_to_harvest);
|
// trace!("Enabled widgets to harvest: {:#?}", self.widgets_to_harvest);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_collected_data(&mut self, used_widgets: UsedWidgets) {
|
pub fn set_collected_data(&mut self, used_widgets: UsedWidgets) {
|
||||||
@ -208,13 +210,6 @@ impl DataCollector {
|
|||||||
// CPU
|
// CPU
|
||||||
if self.widgets_to_harvest.use_cpu {
|
if self.widgets_to_harvest.use_cpu {
|
||||||
self.data.cpu = Some(cpu::get_cpu_data_list(&self.sys, self.show_average_cpu));
|
self.data.cpu = Some(cpu::get_cpu_data_list(&self.sys, self.show_average_cpu));
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
if let Some(cpus) = &self.data.cpu {
|
|
||||||
trace!("cpus: {:#?} results", cpus.len());
|
|
||||||
} else {
|
|
||||||
trace!("Found no cpus.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batteries
|
// Batteries
|
||||||
@ -223,14 +218,6 @@ impl DataCollector {
|
|||||||
self.data.list_of_batteries =
|
self.data.list_of_batteries =
|
||||||
Some(batteries::refresh_batteries(&battery_manager, battery_list));
|
Some(batteries::refresh_batteries(&battery_manager, battery_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
if let Some(batteries) = &self.data.list_of_batteries {
|
|
||||||
trace!("batteries: {:#?} results", batteries.len());
|
|
||||||
} else {
|
|
||||||
trace!("Found no batteries.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.widgets_to_harvest.use_proc {
|
if self.widgets_to_harvest.use_proc {
|
||||||
@ -260,14 +247,6 @@ impl DataCollector {
|
|||||||
} {
|
} {
|
||||||
self.data.list_of_processes = Some(process_list);
|
self.data.list_of_processes = Some(process_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
if let Some(processes) = &self.data.list_of_processes {
|
|
||||||
trace!("processes: {:#?} results", processes.len());
|
|
||||||
} else {
|
|
||||||
trace!("Found no processes.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// I am *well* aware that the sysinfo part w/ blocking code is... not great.
|
// I am *well* aware that the sysinfo part w/ blocking code is... not great.
|
||||||
@ -362,63 +341,26 @@ impl DataCollector {
|
|||||||
self.total_rx = net_data.total_rx;
|
self.total_rx = net_data.total_rx;
|
||||||
self.total_tx = net_data.total_tx;
|
self.total_tx = net_data.total_tx;
|
||||||
self.data.network = Some(net_data);
|
self.data.network = Some(net_data);
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
trace!("Total rx: {:#?}", self.total_rx);
|
|
||||||
trace!("Total tx: {:#?}", self.total_tx);
|
|
||||||
if let Some(network) = &self.data.network {
|
|
||||||
trace!("network rx: {:#?}", network.rx);
|
|
||||||
trace!("network tx: {:#?}", network.tx);
|
|
||||||
} else {
|
|
||||||
trace!("Could not find any networks.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(memory) = mem_res.0 {
|
if let Ok(memory) = mem_res.0 {
|
||||||
self.data.memory = memory;
|
self.data.memory = memory;
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
trace!("mem: {:?} results", self.data.memory);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(swap) = mem_res.1 {
|
if let Ok(swap) = mem_res.1 {
|
||||||
self.data.swap = swap;
|
self.data.swap = swap;
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
trace!("swap: {:?} results", self.data.swap);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(disks) = disk_res {
|
if let Ok(disks) = disk_res {
|
||||||
self.data.disks = disks;
|
self.data.disks = disks;
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
if let Some(disks) = &self.data.disks {
|
|
||||||
trace!("disks: {:#?} results", disks.len());
|
|
||||||
} else {
|
|
||||||
trace!("Could not find any disks.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(io) = io_res {
|
if let Ok(io) = io_res {
|
||||||
self.data.io = io;
|
self.data.io = io;
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
if let Some(io) = &self.data.io {
|
|
||||||
trace!("io: {:#?} results", io.len());
|
|
||||||
} else {
|
|
||||||
trace!("Could not find any io results.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(temp) = temp_res {
|
if let Ok(temp) = temp_res {
|
||||||
self.data.temperature_sensors = temp;
|
self.data.temperature_sensors = temp;
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
if let Some(sensors) = &self.data.temperature_sensors {
|
|
||||||
trace!("temp: {:#?} results", sensors.len());
|
|
||||||
} else {
|
|
||||||
trace!("Could not find any temp sensors.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update time
|
// Update time
|
||||||
|
@ -375,8 +375,10 @@ pub fn get_process_data(
|
|||||||
time_difference_in_secs: u64, mem_total_kb: u64, page_file_kb: u64,
|
time_difference_in_secs: u64, mem_total_kb: u64, page_file_kb: u64,
|
||||||
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
|
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
|
||||||
// TODO: [PROC THREADS] Add threads
|
// TODO: [PROC THREADS] Add threads
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
if let Ok((cpu_usage, cpu_fraction)) = cpu_usage_calculation(prev_idle, prev_non_idle) {
|
if let Ok((cpu_usage, cpu_fraction)) = cpu_usage_calculation(prev_idle, prev_non_idle) {
|
||||||
|
let mut pids_to_clear: HashSet<Pid> = pid_mapping.keys().cloned().collect();
|
||||||
let process_vector: Vec<ProcessHarvest> = std::fs::read_dir("/proc")?
|
let process_vector: Vec<ProcessHarvest> = std::fs::read_dir("/proc")?
|
||||||
.filter_map(|dir| {
|
.filter_map(|dir| {
|
||||||
if let Ok(dir) = dir {
|
if let Ok(dir) = dir {
|
||||||
@ -393,6 +395,7 @@ pub fn get_process_data(
|
|||||||
mem_total_kb,
|
mem_total_kb,
|
||||||
page_file_kb,
|
page_file_kb,
|
||||||
) {
|
) {
|
||||||
|
pids_to_clear.remove(&pid);
|
||||||
return Some(process_object);
|
return Some(process_object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,9 +405,12 @@ pub fn get_process_data(
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
pids_to_clear.iter().for_each(|pid| {
|
||||||
|
pid_mapping.remove(pid);
|
||||||
|
});
|
||||||
|
|
||||||
Ok(process_vector)
|
Ok(process_vector)
|
||||||
} else {
|
} else {
|
||||||
trace!("Could not calculate CPU usage.");
|
|
||||||
Err(BottomError::GenericError(
|
Err(BottomError::GenericError(
|
||||||
"Could not calculate CPU usage.".to_string(),
|
"Could not calculate CPU usage.".to_string(),
|
||||||
))
|
))
|
||||||
|
@ -27,27 +27,24 @@ use tui::{backend::CrosstermBackend, Terminal};
|
|||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let matches = clap::get_matches();
|
let matches = clap::get_matches();
|
||||||
let is_debug = matches.is_present("debug");
|
// let is_debug = matches.is_present("debug");
|
||||||
if is_debug {
|
// if is_debug {
|
||||||
let mut tmp_dir = std::env::temp_dir();
|
// let mut tmp_dir = std::env::temp_dir();
|
||||||
tmp_dir.push("bottom_debug.log");
|
// tmp_dir.push("bottom_debug.log");
|
||||||
utils::logging::init_logger(log::LevelFilter::Trace, tmp_dir.as_os_str())?;
|
// utils::logging::init_logger(log::LevelFilter::Trace, tmp_dir.as_os_str())?;
|
||||||
} else {
|
// } else {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
utils::logging::init_logger(
|
utils::logging::init_logger(log::LevelFilter::Debug, std::ffi::OsStr::new("debug.log"))?;
|
||||||
log::LevelFilter::Debug,
|
|
||||||
std::ffi::OsStr::new("debug.log"),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
let config_path = read_config(matches.value_of("config_location"))
|
let config_path = read_config(matches.value_of("config_location"))
|
||||||
.context("Unable to access the given config file location.")?;
|
.context("Unable to access the given config file location.")?;
|
||||||
trace!("Config path: {:?}", config_path);
|
// trace!("Config path: {:?}", config_path);
|
||||||
let mut config: Config = create_or_get_config(&config_path)
|
let mut config: Config = create_or_get_config(&config_path)
|
||||||
.context("Unable to properly parse or create the config file.")?;
|
.context("Unable to properly parse or create the config file.")?;
|
||||||
trace!("Current config: {:#?}", config);
|
// trace!("Current config: {:#?}", config);
|
||||||
|
|
||||||
// Get widget layout separately
|
// Get widget layout separately
|
||||||
let (widget_layout, default_widget_id, default_widget_type_option) =
|
let (widget_layout, default_widget_id, default_widget_type_option) =
|
||||||
@ -87,29 +84,31 @@ fn main() -> Result<()> {
|
|||||||
let lock = thread_termination_lock.clone();
|
let lock = thread_termination_lock.clone();
|
||||||
let cvar = thread_termination_cvar.clone();
|
let cvar = thread_termination_cvar.clone();
|
||||||
let cleaning_sender = sender.clone();
|
let cleaning_sender = sender.clone();
|
||||||
trace!("Initializing cleaning thread...");
|
const OFFSET_WAIT_TIME: u64 = constants::STALE_MAX_MILLISECONDS + 60000;
|
||||||
|
// trace!("Initializing cleaning thread...");
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
|
// debug!("Starting cleaning loop...");
|
||||||
let result = cvar.wait_timeout(
|
let result = cvar.wait_timeout(
|
||||||
lock.lock().unwrap(),
|
lock.lock().unwrap(),
|
||||||
Duration::from_millis(constants::STALE_MAX_MILLISECONDS + 5000),
|
Duration::from_millis(OFFSET_WAIT_TIME),
|
||||||
);
|
);
|
||||||
|
// debug!("Result mutex guard over...");
|
||||||
if let Ok(result) = result {
|
if let Ok(result) = result {
|
||||||
if *(result.0) {
|
if *(result.0) {
|
||||||
trace!("Received termination lock in cleaning thread from cvar!");
|
// debug!("Received termination lock in cleaning thread from cvar!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
trace!("Sending cleaning signal...");
|
|
||||||
if cleaning_sender.send(BottomEvent::Clean).is_err() {
|
|
||||||
trace!("Failed to send cleaning signal. Halting cleaning thread loop.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
trace!("Cleaning signal sent without errors.");
|
|
||||||
}
|
}
|
||||||
|
// debug!("Sending cleaning signal...");
|
||||||
|
if cleaning_sender.send(BottomEvent::Clean).is_err() {
|
||||||
|
// debug!("Failed to send cleaning sender...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// trace!("Cleaning signal sent without errors.");
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Cleaning thread loop has closed.");
|
// trace!("Cleaning thread loop has closed.");
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,13 +145,6 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
while !is_terminated.load(Ordering::SeqCst) {
|
while !is_terminated.load(Ordering::SeqCst) {
|
||||||
if let Ok(recv) = receiver.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
|
if let Ok(recv) = receiver.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
|
||||||
if log_enabled!(log::Level::Trace) {
|
|
||||||
if let BottomEvent::Update(_) = recv {
|
|
||||||
trace!("Main/drawing thread received Update event.");
|
|
||||||
} else {
|
|
||||||
trace!("Main/drawing thread received event: {:?}", recv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match recv {
|
match recv {
|
||||||
BottomEvent::KeyInput(event) => {
|
BottomEvent::KeyInput(event) => {
|
||||||
if handle_key_event_or_break(event, &mut app, &collection_thread_ctrl_sender) {
|
if handle_key_event_or_break(event, &mut app, &collection_thread_ctrl_sender) {
|
||||||
@ -247,18 +239,18 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [OPT] Should not draw if no change (ie: scroll max)
|
// TODO: [OPT] Should not draw if no change (ie: scroll max)
|
||||||
try_drawing(&mut terminal, &mut app, &mut painter, is_debug)?;
|
try_drawing(&mut terminal, &mut app, &mut painter)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// I think doing it in this order is safe...
|
// I think doing it in this order is safe...
|
||||||
trace!("Send termination thread locks.");
|
// trace!("Send termination thread locks.");
|
||||||
*thread_termination_lock.lock().unwrap() = true;
|
*thread_termination_lock.lock().unwrap() = true;
|
||||||
trace!("Notifying all cvars.");
|
// trace!("Notifying all cvars.");
|
||||||
thread_termination_cvar.notify_all();
|
thread_termination_cvar.notify_all();
|
||||||
|
|
||||||
trace!("Main/drawing thread is cleaning up.");
|
// trace!("Main/drawing thread is cleaning up.");
|
||||||
cleanup_terminal(&mut terminal, is_debug)?;
|
cleanup_terminal(&mut terminal)?;
|
||||||
|
|
||||||
trace!("Fini.");
|
// trace!("Fini.");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
17
src/clap.rs
17
src/clap.rs
@ -81,13 +81,14 @@ custom layouts.\n\n",
|
|||||||
"\
|
"\
|
||||||
When searching for a process, enables case sensitivity by default.\n\n",
|
When searching for a process, enables case sensitivity by default.\n\n",
|
||||||
);
|
);
|
||||||
let debug = Arg::with_name("debug")
|
// TODO: [DEBUG] Add a proper debugging solution.
|
||||||
.long("debug")
|
// let debug = Arg::with_name("debug")
|
||||||
.help("Enables debug logging.")
|
// .long("debug")
|
||||||
.long_help(
|
// .help("Enables debug logging.")
|
||||||
"\
|
// .long_help(
|
||||||
Enables debug logging. The program will print where it logged to after running.",
|
// "\
|
||||||
);
|
// Enables debug logging. The program will print where it logged to after running.",
|
||||||
|
// );
|
||||||
// TODO: [DIAGNOSE] Add a diagnose option to help with debugging.
|
// TODO: [DIAGNOSE] Add a diagnose option to help with debugging.
|
||||||
let disable_click = Arg::with_name("disable_click")
|
let disable_click = Arg::with_name("disable_click")
|
||||||
.long("disable_click")
|
.long("disable_click")
|
||||||
@ -362,7 +363,7 @@ Defaults to showing the process widget in tree mode.\n\n",
|
|||||||
.arg(case_sensitive)
|
.arg(case_sensitive)
|
||||||
.arg(config_location)
|
.arg(config_location)
|
||||||
.arg(color)
|
.arg(color)
|
||||||
.arg(debug)
|
// .arg(debug)
|
||||||
.arg(mem_as_value)
|
.arg(mem_as_value)
|
||||||
.arg(default_time_value)
|
.arg(default_time_value)
|
||||||
.arg(default_widget_count)
|
.arg(default_widget_count)
|
||||||
|
@ -894,6 +894,7 @@ pub fn tree_process_data(
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: [OPT] This is an easy target for optimization, too many to_strings!
|
||||||
pub fn stringify_process_data(
|
pub fn stringify_process_data(
|
||||||
proc_widget_state: &ProcWidgetState, finalized_process_data: &[ConvertedProcessData],
|
proc_widget_state: &ProcWidgetState, finalized_process_data: &[ConvertedProcessData],
|
||||||
) -> Vec<(Vec<(String, Option<String>)>, bool)> {
|
) -> Vec<(Vec<(String, Option<String>)>, bool)> {
|
||||||
|
98
src/lib.rs
98
src/lib.rs
@ -237,10 +237,10 @@ pub fn create_or_get_config(config_path: &Option<PathBuf>) -> error::Result<Conf
|
|||||||
|
|
||||||
pub fn try_drawing(
|
pub fn try_drawing(
|
||||||
terminal: &mut tui::terminal::Terminal<tui::backend::CrosstermBackend<std::io::Stdout>>,
|
terminal: &mut tui::terminal::Terminal<tui::backend::CrosstermBackend<std::io::Stdout>>,
|
||||||
app: &mut App, painter: &mut canvas::Painter, is_debug: bool,
|
app: &mut App, painter: &mut canvas::Painter,
|
||||||
) -> error::Result<()> {
|
) -> error::Result<()> {
|
||||||
if let Err(err) = painter.draw_data(terminal, app) {
|
if let Err(err) = painter.draw_data(terminal, app) {
|
||||||
cleanup_terminal(terminal, is_debug)?;
|
cleanup_terminal(terminal)?;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +249,6 @@ pub fn try_drawing(
|
|||||||
|
|
||||||
pub fn cleanup_terminal(
|
pub fn cleanup_terminal(
|
||||||
terminal: &mut tui::terminal::Terminal<tui::backend::CrosstermBackend<std::io::Stdout>>,
|
terminal: &mut tui::terminal::Terminal<tui::backend::CrosstermBackend<std::io::Stdout>>,
|
||||||
is_debug: bool,
|
|
||||||
) -> error::Result<()> {
|
) -> error::Result<()> {
|
||||||
disable_raw_mode()?;
|
disable_raw_mode()?;
|
||||||
execute!(
|
execute!(
|
||||||
@ -259,11 +258,11 @@ pub fn cleanup_terminal(
|
|||||||
)?;
|
)?;
|
||||||
terminal.show_cursor()?;
|
terminal.show_cursor()?;
|
||||||
|
|
||||||
if is_debug {
|
// if is_debug {
|
||||||
let mut tmp_dir = std::env::temp_dir();
|
// let mut tmp_dir = std::env::temp_dir();
|
||||||
tmp_dir.push("bottom_debug.log");
|
// tmp_dir.push("bottom_debug.log");
|
||||||
println!("Your debug file is located at {:?}", tmp_dir.as_os_str());
|
// println!("Your debug file is located at {:?}", tmp_dir.as_os_str());
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -448,9 +447,7 @@ fn update_final_process_list(app: &mut App, widget_id: u64) {
|
|||||||
fn sort_process_data(
|
fn sort_process_data(
|
||||||
to_sort_vec: &mut Vec<ConvertedProcessData>, proc_widget_state: &app::ProcWidgetState,
|
to_sort_vec: &mut Vec<ConvertedProcessData>, proc_widget_state: &app::ProcWidgetState,
|
||||||
) {
|
) {
|
||||||
to_sort_vec.sort_by(|a, b| {
|
to_sort_vec.sort_by_cached_key(|c| c.name.to_lowercase());
|
||||||
utils::gen_util::get_ordering(&a.name.to_lowercase(), &b.name.to_lowercase(), false)
|
|
||||||
});
|
|
||||||
|
|
||||||
match &proc_widget_state.process_sorting_type {
|
match &proc_widget_state.process_sorting_type {
|
||||||
ProcessSorting::CpuPercent => {
|
ProcessSorting::CpuPercent => {
|
||||||
@ -483,22 +480,18 @@ fn sort_process_data(
|
|||||||
ProcessSorting::ProcessName => {
|
ProcessSorting::ProcessName => {
|
||||||
// Don't repeat if false... it sorts by name by default anyways.
|
// Don't repeat if false... it sorts by name by default anyways.
|
||||||
if proc_widget_state.is_process_sort_descending {
|
if proc_widget_state.is_process_sort_descending {
|
||||||
to_sort_vec.sort_by(|a, b| {
|
to_sort_vec.sort_by_cached_key(|c| c.name.to_lowercase());
|
||||||
utils::gen_util::get_ordering(
|
if proc_widget_state.is_process_sort_descending {
|
||||||
&a.name.to_lowercase(),
|
to_sort_vec.reverse();
|
||||||
&b.name.to_lowercase(),
|
}
|
||||||
proc_widget_state.is_process_sort_descending,
|
}
|
||||||
)
|
}
|
||||||
})
|
ProcessSorting::Command => {
|
||||||
|
to_sort_vec.sort_by_cached_key(|c| c.command.to_lowercase());
|
||||||
|
if proc_widget_state.is_process_sort_descending {
|
||||||
|
to_sort_vec.reverse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ProcessSorting::Command => to_sort_vec.sort_by(|a, b| {
|
|
||||||
utils::gen_util::get_ordering(
|
|
||||||
&a.command.to_lowercase(),
|
|
||||||
&b.command.to_lowercase(),
|
|
||||||
proc_widget_state.is_process_sort_descending,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
ProcessSorting::Pid => {
|
ProcessSorting::Pid => {
|
||||||
if !proc_widget_state.is_grouped {
|
if !proc_widget_state.is_grouped {
|
||||||
to_sort_vec.sort_by(|a, b| {
|
to_sort_vec.sort_by(|a, b| {
|
||||||
@ -546,13 +539,12 @@ fn sort_process_data(
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ProcessSorting::State => to_sort_vec.sort_by(|a, b| {
|
ProcessSorting::State => {
|
||||||
utils::gen_util::get_ordering(
|
to_sort_vec.sort_by_cached_key(|c| c.process_state.to_lowercase());
|
||||||
&a.process_state.to_lowercase(),
|
if proc_widget_state.is_process_sort_descending {
|
||||||
&b.process_state.to_lowercase(),
|
to_sort_vec.reverse();
|
||||||
proc_widget_state.is_process_sort_descending,
|
}
|
||||||
)
|
}
|
||||||
}),
|
|
||||||
ProcessSorting::Count => {
|
ProcessSorting::Count => {
|
||||||
if proc_widget_state.is_grouped {
|
if proc_widget_state.is_grouped {
|
||||||
to_sort_vec.sort_by(|a, b| {
|
to_sort_vec.sort_by(|a, b| {
|
||||||
@ -573,9 +565,9 @@ pub fn create_input_thread(
|
|||||||
>,
|
>,
|
||||||
termination_ctrl_lock: Arc<Mutex<bool>>,
|
termination_ctrl_lock: Arc<Mutex<bool>>,
|
||||||
) -> std::thread::JoinHandle<()> {
|
) -> std::thread::JoinHandle<()> {
|
||||||
trace!("Creating input thread.");
|
// trace!("Creating input thread.");
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
trace!("Spawned input thread.");
|
// trace!("Spawned input thread.");
|
||||||
let mut mouse_timer = Instant::now();
|
let mut mouse_timer = Instant::now();
|
||||||
let mut keyboard_timer = Instant::now();
|
let mut keyboard_timer = Instant::now();
|
||||||
|
|
||||||
@ -583,7 +575,7 @@ pub fn create_input_thread(
|
|||||||
if let Ok(is_terminated) = termination_ctrl_lock.try_lock() {
|
if let Ok(is_terminated) = termination_ctrl_lock.try_lock() {
|
||||||
// We don't block.
|
// We don't block.
|
||||||
if *is_terminated {
|
if *is_terminated {
|
||||||
trace!("Received termination lock in input thread!");
|
// trace!("Received termination lock in input thread!");
|
||||||
drop(is_terminated);
|
drop(is_terminated);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -591,13 +583,13 @@ pub fn create_input_thread(
|
|||||||
if let Ok(poll) = poll(Duration::from_millis(20)) {
|
if let Ok(poll) = poll(Duration::from_millis(20)) {
|
||||||
if poll {
|
if poll {
|
||||||
if let Ok(event) = read() {
|
if let Ok(event) = read() {
|
||||||
trace!("Input thread received an event: {:?}", event);
|
// trace!("Input thread received an event: {:?}", event);
|
||||||
if let Event::Key(key) = event {
|
if let Event::Key(key) = event {
|
||||||
if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 {
|
if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 {
|
||||||
if sender.send(BottomEvent::KeyInput(key)).is_err() {
|
if sender.send(BottomEvent::KeyInput(key)).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
trace!("Input thread sent keyboard data.");
|
// trace!("Input thread sent keyboard data.");
|
||||||
keyboard_timer = Instant::now();
|
keyboard_timer = Instant::now();
|
||||||
}
|
}
|
||||||
} else if let Event::Mouse(mouse) = event {
|
} else if let Event::Mouse(mouse) = event {
|
||||||
@ -605,7 +597,7 @@ pub fn create_input_thread(
|
|||||||
if sender.send(BottomEvent::MouseInput(mouse)).is_err() {
|
if sender.send(BottomEvent::MouseInput(mouse)).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
trace!("Input thread sent mouse data.");
|
// trace!("Input thread sent mouse data.");
|
||||||
mouse_timer = Instant::now();
|
mouse_timer = Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -613,7 +605,7 @@ pub fn create_input_thread(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trace!("Input thread loop has closed.");
|
// trace!("Input thread loop has closed.");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,39 +617,39 @@ pub fn create_collection_thread(
|
|||||||
termination_ctrl_lock: Arc<Mutex<bool>>, termination_ctrl_cvar: Arc<Condvar>,
|
termination_ctrl_lock: Arc<Mutex<bool>>, termination_ctrl_cvar: Arc<Condvar>,
|
||||||
app_config_fields: &app::AppConfigFields, used_widget_set: UsedWidgets,
|
app_config_fields: &app::AppConfigFields, used_widget_set: UsedWidgets,
|
||||||
) -> std::thread::JoinHandle<()> {
|
) -> std::thread::JoinHandle<()> {
|
||||||
trace!("Creating collection thread.");
|
// trace!("Creating collection thread.");
|
||||||
let temp_type = app_config_fields.temperature_type.clone();
|
let temp_type = app_config_fields.temperature_type.clone();
|
||||||
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 show_average_cpu = app_config_fields.show_average_cpu;
|
let show_average_cpu = app_config_fields.show_average_cpu;
|
||||||
let update_rate_in_milliseconds = app_config_fields.update_rate_in_milliseconds;
|
let update_rate_in_milliseconds = app_config_fields.update_rate_in_milliseconds;
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
trace!("Spawned collection thread.");
|
// trace!("Spawned collection thread.");
|
||||||
let mut data_state = data_harvester::DataCollector::default();
|
let mut data_state = data_harvester::DataCollector::default();
|
||||||
trace!("Created default data state.");
|
// trace!("Created default data state.");
|
||||||
data_state.set_collected_data(used_widget_set);
|
data_state.set_collected_data(used_widget_set);
|
||||||
data_state.set_temperature_type(temp_type);
|
data_state.set_temperature_type(temp_type);
|
||||||
data_state.set_use_current_cpu_total(use_current_cpu_total);
|
data_state.set_use_current_cpu_total(use_current_cpu_total);
|
||||||
data_state.set_show_average_cpu(show_average_cpu);
|
data_state.set_show_average_cpu(show_average_cpu);
|
||||||
trace!("Set default data state settings.");
|
// trace!("Set default data state settings.");
|
||||||
|
|
||||||
data_state.init();
|
data_state.init();
|
||||||
trace!("Data state is now fully initialized.");
|
// trace!("Data state is now fully initialized.");
|
||||||
loop {
|
loop {
|
||||||
// Check once at the very top...
|
// Check once at the very top...
|
||||||
if let Ok(is_terminated) = termination_ctrl_lock.try_lock() {
|
if let Ok(is_terminated) = termination_ctrl_lock.try_lock() {
|
||||||
// We don't block here.
|
// We don't block here.
|
||||||
if *is_terminated {
|
if *is_terminated {
|
||||||
trace!("Received termination lock in collection thread!");
|
// trace!("Received termination lock in collection thread!");
|
||||||
drop(is_terminated);
|
drop(is_terminated);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Checking for collection control receiver event...");
|
// trace!("Checking for collection control receiver event...");
|
||||||
let mut update_time = update_rate_in_milliseconds;
|
let mut update_time = update_rate_in_milliseconds;
|
||||||
if let Ok(message) = control_receiver.try_recv() {
|
if let Ok(message) = control_receiver.try_recv() {
|
||||||
trace!("Received message in collection thread: {:?}", message);
|
// trace!("Received message in collection thread: {:?}", message);
|
||||||
match message {
|
match message {
|
||||||
ThreadControlEvent::Reset => {
|
ThreadControlEvent::Reset => {
|
||||||
data_state.data.cleanup();
|
data_state.data.cleanup();
|
||||||
@ -682,32 +674,32 @@ pub fn create_collection_thread(
|
|||||||
if let Ok(is_terminated) = termination_ctrl_lock.try_lock() {
|
if let Ok(is_terminated) = termination_ctrl_lock.try_lock() {
|
||||||
// We don't block here.
|
// We don't block here.
|
||||||
if *is_terminated {
|
if *is_terminated {
|
||||||
trace!("Received termination lock in collection thread!");
|
// trace!("Received termination lock in collection thread!");
|
||||||
drop(is_terminated);
|
drop(is_terminated);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Collection thread is updating and sending...");
|
// trace!("Collection thread is updating and sending...");
|
||||||
let event = BottomEvent::Update(Box::from(data_state.data));
|
let event = BottomEvent::Update(Box::from(data_state.data));
|
||||||
data_state.data = data_harvester::Data::default();
|
data_state.data = data_harvester::Data::default();
|
||||||
if sender.send(event).is_err() {
|
if sender.send(event).is_err() {
|
||||||
trace!("Error sending from collection thread...");
|
// trace!("Error sending from collection thread...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
trace!("No problem sending from collection thread!");
|
// trace!("No problem sending from collection thread!");
|
||||||
|
|
||||||
if let Ok((is_terminated, _wait_timeout_result)) = termination_ctrl_cvar.wait_timeout(
|
if let Ok((is_terminated, _wait_timeout_result)) = termination_ctrl_cvar.wait_timeout(
|
||||||
termination_ctrl_lock.lock().unwrap(),
|
termination_ctrl_lock.lock().unwrap(),
|
||||||
Duration::from_millis(update_time),
|
Duration::from_millis(update_time),
|
||||||
) {
|
) {
|
||||||
if *is_terminated {
|
if *is_terminated {
|
||||||
trace!("Received termination lock in collection thread from cvar!");
|
// trace!("Received termination lock in collection thread from cvar!");
|
||||||
drop(is_terminated);
|
drop(is_terminated);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trace!("Collection thread loop has closed.");
|
// trace!("Collection thread loop has closed.");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user