mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-22 20:23:12 +00:00
Added average cpu option.
This commit is contained in:
parent
6d9ed34dcb
commit
b14432c3df
5 changed files with 186 additions and 172 deletions
160
src/app.rs
160
src/app.rs
|
@ -1,8 +1,5 @@
|
|||
pub mod data_collection;
|
||||
use data_collection::{cpu, disks, mem, network, processes, temperature};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use sysinfo::{System, SystemExt};
|
||||
use data_collection::{processes, temperature};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct App {
|
||||
|
@ -11,167 +8,22 @@ pub struct App {
|
|||
pub process_sorting_reverse : bool,
|
||||
pub to_be_resorted : bool,
|
||||
pub current_selected_process_position : u64,
|
||||
pub temperature_type : data_collection::temperature::TemperatureType,
|
||||
pub temperature_type : temperature::TemperatureType,
|
||||
pub update_rate_in_milliseconds : u64,
|
||||
}
|
||||
|
||||
fn set_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, value_to_set : &mut T) {
|
||||
if let Ok(result) = result {
|
||||
*value_to_set = (*result).clone();
|
||||
}
|
||||
}
|
||||
|
||||
fn push_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, vector_to_push : &mut Vec<T>) {
|
||||
if let Ok(result) = result {
|
||||
vector_to_push.push(result.clone());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Data {
|
||||
pub list_of_cpu_packages : Vec<cpu::CPUPackage>,
|
||||
pub list_of_io : Vec<disks::IOPackage>,
|
||||
pub list_of_physical_io : Vec<disks::IOPackage>,
|
||||
pub memory : Vec<mem::MemData>,
|
||||
pub swap : Vec<mem::MemData>,
|
||||
pub list_of_temperature_sensor : Vec<temperature::TempData>,
|
||||
pub network : Vec<network::NetworkData>,
|
||||
pub list_of_processes : Vec<processes::ProcessData>, // Only need to keep a list of processes...
|
||||
pub list_of_disks : Vec<disks::DiskData>, // Only need to keep a list of disks and their data
|
||||
}
|
||||
|
||||
pub struct DataState {
|
||||
pub data : Data,
|
||||
first_run : bool,
|
||||
sys : System,
|
||||
stale_max_seconds : u64,
|
||||
prev_pid_stats : HashMap<String, f64>, // TODO: Purge list?
|
||||
prev_idle : f64,
|
||||
prev_non_idle : f64,
|
||||
temperature_type : data_collection::temperature::TemperatureType,
|
||||
}
|
||||
|
||||
impl Default for DataState {
|
||||
fn default() -> Self {
|
||||
DataState {
|
||||
data : Data::default(),
|
||||
first_run : true,
|
||||
sys : System::new(),
|
||||
stale_max_seconds : 60,
|
||||
prev_pid_stats : HashMap::new(),
|
||||
prev_idle : 0_f64,
|
||||
prev_non_idle : 0_f64,
|
||||
temperature_type : data_collection::temperature::TemperatureType::Celsius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataState {
|
||||
pub fn set_stale_max_seconds(&mut self, stale_max_seconds : u64) {
|
||||
self.stale_max_seconds = stale_max_seconds;
|
||||
}
|
||||
|
||||
pub fn set_temperature_type(&mut self, temperature_type : data_collection::temperature::TemperatureType) {
|
||||
self.temperature_type = temperature_type;
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.sys.refresh_system();
|
||||
self.sys.refresh_network();
|
||||
}
|
||||
|
||||
pub async fn update_data(&mut self) {
|
||||
debug!("Start updating...");
|
||||
self.sys.refresh_system();
|
||||
self.sys.refresh_network();
|
||||
|
||||
// What we want to do: For timed data, if there is an error, just do not add. For other data, just don't update!
|
||||
push_if_valid(&network::get_network_data(&self.sys), &mut self.data.network);
|
||||
push_if_valid(&cpu::get_cpu_data_list(&self.sys), &mut self.data.list_of_cpu_packages);
|
||||
|
||||
// TODO: We can convert this to a multi-threaded task...
|
||||
push_if_valid(&mem::get_mem_data_list().await, &mut self.data.memory);
|
||||
push_if_valid(&mem::get_swap_data_list().await, &mut self.data.swap);
|
||||
set_if_valid(
|
||||
&processes::get_sorted_processes_list(&mut self.prev_idle, &mut self.prev_non_idle, &mut self.prev_pid_stats).await,
|
||||
&mut self.data.list_of_processes,
|
||||
);
|
||||
|
||||
set_if_valid(&disks::get_disk_usage_list().await, &mut self.data.list_of_disks);
|
||||
push_if_valid(&disks::get_io_usage_list(false).await, &mut self.data.list_of_io);
|
||||
push_if_valid(&disks::get_io_usage_list(true).await, &mut self.data.list_of_physical_io);
|
||||
set_if_valid(&temperature::get_temperature_data(&self.temperature_type).await, &mut self.data.list_of_temperature_sensor);
|
||||
|
||||
if self.first_run {
|
||||
self.data = Data::default();
|
||||
self.first_run = false;
|
||||
}
|
||||
|
||||
// Filter out stale timed entries
|
||||
// TODO: ideally make this a generic function!
|
||||
let current_instant = std::time::Instant::now();
|
||||
self.data.list_of_cpu_packages = self
|
||||
.data
|
||||
.list_of_cpu_packages
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.memory = self
|
||||
.data
|
||||
.memory
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.swap = self
|
||||
.data
|
||||
.swap
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.network = self
|
||||
.data
|
||||
.network
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.list_of_io = self
|
||||
.data
|
||||
.list_of_io
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.list_of_physical_io = self
|
||||
.data
|
||||
.list_of_physical_io
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
debug!("End updating...");
|
||||
}
|
||||
pub show_average_cpu : bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(temperature_type : data_collection::temperature::TemperatureType, update_rate_in_milliseconds : u64) -> App {
|
||||
pub fn new(show_average_cpu : bool, temperature_type : temperature::TemperatureType, update_rate_in_milliseconds : u64) -> App {
|
||||
App {
|
||||
process_sorting_type : processes::ProcessSorting::CPU, // TODO: Change this based on input args... basically set this on app creation
|
||||
process_sorting_type : processes::ProcessSorting::CPU,
|
||||
should_quit : false,
|
||||
process_sorting_reverse : true,
|
||||
to_be_resorted : false,
|
||||
current_selected_process_position : 0,
|
||||
temperature_type,
|
||||
update_rate_in_milliseconds,
|
||||
show_average_cpu,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,156 @@
|
|||
use std::collections::HashMap;
|
||||
use sysinfo::{System, SystemExt};
|
||||
|
||||
pub mod cpu;
|
||||
pub mod disks;
|
||||
pub mod mem;
|
||||
pub mod network;
|
||||
pub mod processes;
|
||||
pub mod temperature;
|
||||
|
||||
fn set_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, value_to_set : &mut T) {
|
||||
if let Ok(result) = result {
|
||||
*value_to_set = (*result).clone();
|
||||
}
|
||||
}
|
||||
|
||||
fn push_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, vector_to_push : &mut Vec<T>) {
|
||||
if let Ok(result) = result {
|
||||
vector_to_push.push(result.clone());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Data {
|
||||
pub list_of_cpu_packages : Vec<cpu::CPUPackage>,
|
||||
pub list_of_io : Vec<disks::IOPackage>,
|
||||
pub list_of_physical_io : Vec<disks::IOPackage>,
|
||||
pub memory : Vec<mem::MemData>,
|
||||
pub swap : Vec<mem::MemData>,
|
||||
pub list_of_temperature_sensor : Vec<temperature::TempData>,
|
||||
pub network : Vec<network::NetworkData>,
|
||||
pub list_of_processes : Vec<processes::ProcessData>, // Only need to keep a list of processes...
|
||||
pub list_of_disks : Vec<disks::DiskData>, // Only need to keep a list of disks and their data
|
||||
}
|
||||
|
||||
pub struct DataState {
|
||||
pub data : Data,
|
||||
first_run : bool,
|
||||
sys : System,
|
||||
stale_max_seconds : u64,
|
||||
prev_pid_stats : HashMap<String, f64>, // TODO: Purge list?
|
||||
prev_idle : f64,
|
||||
prev_non_idle : f64,
|
||||
temperature_type : temperature::TemperatureType,
|
||||
}
|
||||
|
||||
impl Default for DataState {
|
||||
fn default() -> Self {
|
||||
DataState {
|
||||
data : Data::default(),
|
||||
first_run : true,
|
||||
sys : System::new(),
|
||||
stale_max_seconds : 60,
|
||||
prev_pid_stats : HashMap::new(),
|
||||
prev_idle : 0_f64,
|
||||
prev_non_idle : 0_f64,
|
||||
temperature_type : temperature::TemperatureType::Celsius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataState {
|
||||
pub fn set_stale_max_seconds(&mut self, stale_max_seconds : u64) {
|
||||
self.stale_max_seconds = stale_max_seconds;
|
||||
}
|
||||
|
||||
pub fn set_temperature_type(&mut self, temperature_type : temperature::TemperatureType) {
|
||||
self.temperature_type = temperature_type;
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.sys.refresh_system();
|
||||
self.sys.refresh_network();
|
||||
}
|
||||
|
||||
pub async fn update_data(&mut self) {
|
||||
debug!("Start updating...");
|
||||
self.sys.refresh_system();
|
||||
self.sys.refresh_network();
|
||||
|
||||
// What we want to do: For timed data, if there is an error, just do not add. For other data, just don't update!
|
||||
push_if_valid(&network::get_network_data(&self.sys), &mut self.data.network);
|
||||
push_if_valid(&cpu::get_cpu_data_list(&self.sys), &mut self.data.list_of_cpu_packages);
|
||||
|
||||
// TODO: We can convert this to a multi-threaded task...
|
||||
push_if_valid(&mem::get_mem_data_list().await, &mut self.data.memory);
|
||||
push_if_valid(&mem::get_swap_data_list().await, &mut self.data.swap);
|
||||
set_if_valid(
|
||||
&processes::get_sorted_processes_list(&mut self.prev_idle, &mut self.prev_non_idle, &mut self.prev_pid_stats).await,
|
||||
&mut self.data.list_of_processes,
|
||||
);
|
||||
|
||||
set_if_valid(&disks::get_disk_usage_list().await, &mut self.data.list_of_disks);
|
||||
push_if_valid(&disks::get_io_usage_list(false).await, &mut self.data.list_of_io);
|
||||
push_if_valid(&disks::get_io_usage_list(true).await, &mut self.data.list_of_physical_io);
|
||||
set_if_valid(&temperature::get_temperature_data(&self.temperature_type).await, &mut self.data.list_of_temperature_sensor);
|
||||
|
||||
if self.first_run {
|
||||
self.data = Data::default();
|
||||
self.first_run = false;
|
||||
}
|
||||
|
||||
// Filter out stale timed entries
|
||||
// TODO: ideally make this a generic function!
|
||||
let current_instant = std::time::Instant::now();
|
||||
self.data.list_of_cpu_packages = self
|
||||
.data
|
||||
.list_of_cpu_packages
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.memory = self
|
||||
.data
|
||||
.memory
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.swap = self
|
||||
.data
|
||||
.swap
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.network = self
|
||||
.data
|
||||
.network
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.list_of_io = self
|
||||
.data
|
||||
.list_of_io
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.list_of_physical_io = self
|
||||
.data
|
||||
.list_of_physical_io
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|entry| current_instant.duration_since(entry.instant).as_secs() <= self.stale_max_seconds)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
debug!("End updating...");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,12 @@ pub enum ProcessSorting {
|
|||
NAME,
|
||||
}
|
||||
|
||||
impl Default for ProcessSorting {
|
||||
fn default() -> Self {
|
||||
ProcessSorting::CPU
|
||||
}
|
||||
}
|
||||
|
||||
// Possible process info struct?
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ProcessData {
|
||||
|
|
|
@ -13,6 +13,12 @@ pub enum TemperatureType {
|
|||
Fahrenheit,
|
||||
}
|
||||
|
||||
impl Default for TemperatureType {
|
||||
fn default() -> Self {
|
||||
TemperatureType::Celsius
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_temperature_data(temp_type : &TemperatureType) -> Result<Vec<TempData>, heim::Error> {
|
||||
let mut temperature_vec : Vec<TempData> = Vec::new();
|
||||
|
||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -21,7 +21,7 @@ extern crate clap;
|
|||
|
||||
enum Event<I> {
|
||||
Input(I),
|
||||
Update(Box<app::Data>),
|
||||
Update(Box<app::data_collection::Data>),
|
||||
}
|
||||
|
||||
const STALE_MAX_MILLISECONDS : u64 = 60 * 1000;
|
||||
|
@ -37,11 +37,11 @@ async fn main() -> Result<(), io::Error> {
|
|||
(author: "Clement Tsang <clementjhtsang@gmail.com>")
|
||||
(about: "A graphical top clone.")
|
||||
(@arg THEME: -t --theme +takes_value "Sets a colour theme.")
|
||||
(@arg AVG_CPU: -a --avgcpu "Enables showing the average CPU usage.")
|
||||
(@group TEMPERATURE_TYPE =>
|
||||
(@arg celsius : -c --celsius "Sets the temperature type to Celsius. This is the default option.")
|
||||
(@arg fahrenheit : -f --fahrenheit "Sets the temperature type to Fahrenheit.")
|
||||
(@arg kelvin : -k --kelvin "Sets the temperature type to Kelvin.")
|
||||
|
||||
)
|
||||
(@arg RATE: -r --rate +takes_value "Sets a refresh rate in milliseconds, min is 250ms, defaults to 1000ms. Higher values may take more resources.")
|
||||
)
|
||||
|
@ -62,10 +62,9 @@ async fn main() -> Result<(), io::Error> {
|
|||
else {
|
||||
app::data_collection::temperature::TemperatureType::Celsius
|
||||
};
|
||||
let show_average_cpu = matches.is_present("AVG_CPU");
|
||||
|
||||
info!("Temperature type: {:?}", temperature_type);
|
||||
|
||||
let mut app = app::App::new(temperature_type, if update_rate_in_milliseconds < 250 { 250 } else { update_rate_in_milliseconds });
|
||||
let mut app = app::App::new(show_average_cpu, temperature_type, if update_rate_in_milliseconds < 250 { 250 } else { update_rate_in_milliseconds });
|
||||
|
||||
terminal.hide_cursor()?;
|
||||
// Setup input handling
|
||||
|
@ -86,7 +85,7 @@ async fn main() -> Result<(), io::Error> {
|
|||
}
|
||||
|
||||
// Event loop
|
||||
let mut data_state = app::DataState::default();
|
||||
let mut data_state = app::data_collection::DataState::default();
|
||||
data_state.init();
|
||||
data_state.set_stale_max_seconds(STALE_MAX_MILLISECONDS);
|
||||
data_state.set_temperature_type(app.temperature_type.clone());
|
||||
|
@ -104,7 +103,7 @@ async fn main() -> Result<(), io::Error> {
|
|||
|
||||
terminal.clear()?;
|
||||
|
||||
let mut app_data = app::Data::default();
|
||||
let mut app_data = app::data_collection::Data::default();
|
||||
let mut canvas_data = canvas::CanvasData::default();
|
||||
|
||||
loop {
|
||||
|
@ -140,7 +139,7 @@ async fn main() -> Result<(), io::Error> {
|
|||
canvas_data.process_data = update_process_row(&app_data);
|
||||
canvas_data.mem_data = update_mem_data_points(&app_data);
|
||||
canvas_data.swap_data = update_swap_data_points(&app_data);
|
||||
canvas_data.cpu_data = update_cpu_data_points(&app_data);
|
||||
canvas_data.cpu_data = update_cpu_data_points(app.show_average_cpu, &app_data);
|
||||
|
||||
debug!("Update event complete.");
|
||||
}
|
||||
|
@ -156,7 +155,7 @@ async fn main() -> Result<(), io::Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn update_temp_row(app_data : &app::Data, temp_type : &app::data_collection::temperature::TemperatureType) -> Vec<Vec<String>> {
|
||||
fn update_temp_row(app_data : &app::data_collection::Data, temp_type : &app::data_collection::temperature::TemperatureType) -> Vec<Vec<String>> {
|
||||
let mut sensor_vector : Vec<Vec<String>> = Vec::new();
|
||||
|
||||
for sensor in &app_data.list_of_temperature_sensor {
|
||||
|
@ -174,7 +173,7 @@ fn update_temp_row(app_data : &app::Data, temp_type : &app::data_collection::tem
|
|||
sensor_vector
|
||||
}
|
||||
|
||||
fn update_disk_row(app_data : &app::Data) -> Vec<Vec<String>> {
|
||||
fn update_disk_row(app_data : &app::data_collection::Data) -> Vec<Vec<String>> {
|
||||
let mut disk_vector : Vec<Vec<String>> = Vec::new();
|
||||
for disk in &app_data.list_of_disks {
|
||||
disk_vector.push(vec![
|
||||
|
@ -189,7 +188,7 @@ fn update_disk_row(app_data : &app::Data) -> Vec<Vec<String>> {
|
|||
disk_vector
|
||||
}
|
||||
|
||||
fn update_process_row(app_data : &app::Data) -> Vec<Vec<String>> {
|
||||
fn update_process_row(app_data : &app::data_collection::Data) -> Vec<Vec<String>> {
|
||||
let mut process_vector : Vec<Vec<String>> = Vec::new();
|
||||
|
||||
for process in &app_data.list_of_processes {
|
||||
|
@ -220,15 +219,15 @@ fn update_process_row(app_data : &app::Data) -> Vec<Vec<String>> {
|
|||
process_vector
|
||||
}
|
||||
|
||||
fn update_cpu_data_points(app_data : &app::Data) -> Vec<(String, Vec<(f64, f64)>)> {
|
||||
fn update_cpu_data_points(show_avg_cpu : bool, app_data : &app::data_collection::Data) -> Vec<(String, Vec<(f64, f64)>)> {
|
||||
let mut cpu_data_vector : Vec<(String, Vec<(f64, f64)>)> = Vec::new();
|
||||
let mut cpu_collection : Vec<Vec<(f64, f64)>> = Vec::new();
|
||||
|
||||
if !app_data.list_of_cpu_packages.is_empty() {
|
||||
// Initially, populate the cpu_collection. We want to inject elements in between if possible.
|
||||
|
||||
for cpu_num in 1..app_data.list_of_cpu_packages.last().unwrap().cpu_vec.len() {
|
||||
// TODO: 1 to skip total cpu? Or no?
|
||||
// I'm sorry for the if statement but I couldn't be bothered here...
|
||||
for cpu_num in (if show_avg_cpu { 0 } else { 1 })..app_data.list_of_cpu_packages.last().unwrap().cpu_vec.len() {
|
||||
let mut this_cpu_data : Vec<(f64, f64)> = Vec::new();
|
||||
|
||||
for data in &app_data.list_of_cpu_packages {
|
||||
|
@ -246,8 +245,9 @@ fn update_cpu_data_points(app_data : &app::Data) -> Vec<(String, Vec<(f64, f64)>
|
|||
// Finally, add it all onto the end
|
||||
for (i, data) in cpu_collection.iter().enumerate() {
|
||||
cpu_data_vector.push((
|
||||
// + 1 to skip total CPU...
|
||||
(&*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i + 1].cpu_name)).to_string() + " " + &format!("{:3}%", (data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64)),
|
||||
// + 1 to skip total CPU if show_avg_cpu is false
|
||||
(&*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i + if show_avg_cpu { 0 } else { 1 }].cpu_name)).to_string()
|
||||
+ " " + &format!("{:3}%", (data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64)),
|
||||
data.clone(),
|
||||
))
|
||||
}
|
||||
|
@ -256,11 +256,11 @@ fn update_cpu_data_points(app_data : &app::Data) -> Vec<(String, Vec<(f64, f64)>
|
|||
cpu_data_vector
|
||||
}
|
||||
|
||||
fn update_mem_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
|
||||
fn update_mem_data_points(app_data : &app::data_collection::Data) -> Vec<(f64, f64)> {
|
||||
convert_mem_data(&app_data.memory)
|
||||
}
|
||||
|
||||
fn update_swap_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
|
||||
fn update_swap_data_points(app_data : &app::data_collection::Data) -> Vec<(f64, f64)> {
|
||||
convert_mem_data(&app_data.swap)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue