feat: process list
this is unnacceptably unperformant; I think I've reached the point at which sysinfo doesn't do what I want, which is keep track of a table of processes efficiently enough.
This commit is contained in:
parent
afa6104c28
commit
b20158820b
4 changed files with 105 additions and 22 deletions
|
|
@ -8,7 +8,10 @@ use iced::{
|
||||||
use ron::de;
|
use ron::de;
|
||||||
use smol::{Timer, unblock};
|
use smol::{Timer, unblock};
|
||||||
|
|
||||||
use crate::{app, sysinfo_snapshot::SysinfoSnapshot};
|
use crate::{
|
||||||
|
app,
|
||||||
|
sysinfo_snapshot::{self, SysinfoSnapshot},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn create() -> Task<app::Message> {
|
pub fn create() -> Task<app::Message> {
|
||||||
if env::args()
|
if env::args()
|
||||||
|
|
@ -43,9 +46,7 @@ pub fn create() -> Task<app::Message> {
|
||||||
1,
|
1,
|
||||||
async |mut sender: futures::channel::mpsc::Sender<SysinfoSnapshot>| {
|
async |mut sender: futures::channel::mpsc::Sender<SysinfoSnapshot>| {
|
||||||
let mut sys = sysinfo::System::new();
|
let mut sys = sysinfo::System::new();
|
||||||
let refreshes = sysinfo::RefreshKind::nothing()
|
let refreshes = sysinfo_snapshot::refreshes();
|
||||||
.with_memory(sysinfo::MemoryRefreshKind::everything())
|
|
||||||
.with_cpu(sysinfo::CpuRefreshKind::nothing().with_cpu_usage());
|
|
||||||
|
|
||||||
sys.refresh_specifics(refreshes);
|
sys.refresh_specifics(refreshes);
|
||||||
Timer::after(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL).await;
|
Timer::after(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL).await;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use iced::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{graph::Graph, utils::maybe_widget},
|
app::{graph::Graph, utils::maybe_widget},
|
||||||
sysinfo_snapshot::SysinfoSnapshot,
|
sysinfo_snapshot::{ProcessSnapshot, SysinfoSnapshot},
|
||||||
utils::Toggle,
|
utils::Toggle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -22,6 +22,7 @@ enum Message {
|
||||||
ToggleMain,
|
ToggleMain,
|
||||||
ToggleCpu,
|
ToggleCpu,
|
||||||
ToggleMemory,
|
ToggleMemory,
|
||||||
|
ToggleProcesses,
|
||||||
|
|
||||||
Info(SysinfoSnapshot),
|
Info(SysinfoSnapshot),
|
||||||
}
|
}
|
||||||
|
|
@ -39,6 +40,9 @@ struct State {
|
||||||
is_memory_section_shown: bool,
|
is_memory_section_shown: bool,
|
||||||
memory_graph: Graph,
|
memory_graph: Graph,
|
||||||
swap_graph: Graph,
|
swap_graph: Graph,
|
||||||
|
|
||||||
|
is_processes_section_shown: bool,
|
||||||
|
processes: Vec<ProcessSnapshot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
|
@ -65,6 +69,10 @@ impl State {
|
||||||
self.is_memory_section_shown.toggle();
|
self.is_memory_section_shown.toggle();
|
||||||
self.check_borders();
|
self.check_borders();
|
||||||
}
|
}
|
||||||
|
Message::ToggleProcesses => {
|
||||||
|
self.is_processes_section_shown.toggle();
|
||||||
|
self.check_borders();
|
||||||
|
}
|
||||||
|
|
||||||
Message::Info(snapshot) => {
|
Message::Info(snapshot) => {
|
||||||
self.uptime = snapshot.uptime();
|
self.uptime = snapshot.uptime();
|
||||||
|
|
@ -89,6 +97,10 @@ impl State {
|
||||||
.zip(snapshot.cpus.into_iter())
|
.zip(snapshot.cpus.into_iter())
|
||||||
.for_each(|(graph, value)| graph.update(value));
|
.for_each(|(graph, value)| graph.update(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.processes = snapshot.processes;
|
||||||
|
self.processes
|
||||||
|
.sort_by(|a, b| b.cpu_usage.total_cmp(&a.cpu_usage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,19 +127,39 @@ impl State {
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
.into(),
|
.into(),
|
||||||
maybe_widget(self.is_memory_section_shown, || {
|
widget::row([
|
||||||
widget::row([
|
maybe_widget(self.is_memory_section_shown, || {
|
||||||
widget::canvas(&self.memory_graph)
|
widget::row([
|
||||||
.width(Length::Fill)
|
widget::canvas(&self.memory_graph)
|
||||||
.height(Length::Fill)
|
.width(Length::Fill)
|
||||||
.into(),
|
.height(Length::Fill)
|
||||||
widget::canvas(&self.swap_graph)
|
.into(),
|
||||||
.width(Length::Fill)
|
widget::canvas(&self.swap_graph)
|
||||||
.height(Length::Fill)
|
.width(Length::Fill)
|
||||||
.into(),
|
.height(Length::Fill)
|
||||||
])
|
.into(),
|
||||||
.into()
|
])
|
||||||
}),
|
.into()
|
||||||
|
}),
|
||||||
|
maybe_widget(self.is_processes_section_shown, || {
|
||||||
|
widget::scrollable(
|
||||||
|
widget::grid(self.processes.iter().flat_map(|process| {
|
||||||
|
[
|
||||||
|
widget::text(&process.name).into(),
|
||||||
|
widget::text(process.cpu_usage).into(),
|
||||||
|
widget::text(format!("{:?}", process.cpu_time())).into(),
|
||||||
|
widget::text(process.pid).into(),
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
.height(Length::Shrink)
|
||||||
|
.columns(4),
|
||||||
|
)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
.into(),
|
||||||
])
|
])
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
@ -139,6 +171,7 @@ impl State {
|
||||||
Key::Character("M" | "1") => Some(Message::ToggleMain),
|
Key::Character("M" | "1") => Some(Message::ToggleMain),
|
||||||
Key::Character("c" | "2") => Some(Message::ToggleCpu),
|
Key::Character("c" | "2") => Some(Message::ToggleCpu),
|
||||||
Key::Character("m" | "3") => Some(Message::ToggleMemory),
|
Key::Character("m" | "3") => Some(Message::ToggleMemory),
|
||||||
|
Key::Character("p" | "4") => Some(Message::ToggleProcesses),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,11 @@ use std::{io::Write, thread};
|
||||||
|
|
||||||
use ron::{Error, ser};
|
use ron::{Error, ser};
|
||||||
|
|
||||||
use crate::sysinfo_snapshot::SysinfoSnapshot;
|
use crate::sysinfo_snapshot::{self, SysinfoSnapshot};
|
||||||
|
|
||||||
pub fn run() -> Result<(), Error> {
|
pub fn run() -> Result<(), Error> {
|
||||||
let mut sys = sysinfo::System::new();
|
let mut sys = sysinfo::System::new();
|
||||||
let refreshes = sysinfo::RefreshKind::nothing()
|
let refreshes = sysinfo_snapshot::refreshes();
|
||||||
.with_memory(sysinfo::MemoryRefreshKind::everything())
|
|
||||||
.with_cpu(sysinfo::CpuRefreshKind::nothing().with_cpu_usage());
|
|
||||||
|
|
||||||
sys.refresh_specifics(refreshes);
|
sys.refresh_specifics(refreshes);
|
||||||
thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
|
thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,20 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub fn refreshes() -> sysinfo::RefreshKind {
|
||||||
|
sysinfo::RefreshKind::nothing()
|
||||||
|
.with_memory(sysinfo::MemoryRefreshKind::everything())
|
||||||
|
.with_cpu(sysinfo::CpuRefreshKind::nothing().with_cpu_usage())
|
||||||
|
.with_processes(
|
||||||
|
sysinfo::ProcessRefreshKind::nothing()
|
||||||
|
.with_cpu()
|
||||||
|
.with_cmd(sysinfo::UpdateKind::OnlyIfNotSet)
|
||||||
|
.with_exe(sysinfo::UpdateKind::OnlyIfNotSet),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct SysinfoSnapshot {
|
pub struct SysinfoSnapshot {
|
||||||
|
/// in seconds
|
||||||
uptime: u64,
|
uptime: u64,
|
||||||
|
|
||||||
pub cpu_total: f32,
|
pub cpu_total: f32,
|
||||||
|
|
@ -11,6 +24,8 @@ pub struct SysinfoSnapshot {
|
||||||
pub memory_total: u64,
|
pub memory_total: u64,
|
||||||
pub swap: u64,
|
pub swap: u64,
|
||||||
pub swap_total: u64,
|
pub swap_total: u64,
|
||||||
|
|
||||||
|
pub processes: Vec<ProcessSnapshot>,
|
||||||
}
|
}
|
||||||
impl SysinfoSnapshot {
|
impl SysinfoSnapshot {
|
||||||
#[cfg_attr(not(feature = "app"), allow(dead_code))]
|
#[cfg_attr(not(feature = "app"), allow(dead_code))]
|
||||||
|
|
@ -31,6 +46,42 @@ impl From<&sysinfo::System> for SysinfoSnapshot {
|
||||||
memory_total: value.total_memory(),
|
memory_total: value.total_memory(),
|
||||||
swap: value.used_swap(),
|
swap: value.used_swap(),
|
||||||
swap_total: value.total_swap(),
|
swap_total: value.total_swap(),
|
||||||
|
|
||||||
|
processes: value
|
||||||
|
.processes()
|
||||||
|
.iter()
|
||||||
|
.map(|(_pid, process)| ProcessSnapshot::from(process))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct ProcessSnapshot {
|
||||||
|
pub pid: usize,
|
||||||
|
|
||||||
|
/// in CPU-milliseconds
|
||||||
|
accumulated_cpu_time: u64,
|
||||||
|
|
||||||
|
/// note: it's by core, and can be up to eg 1600 on a 16-core device
|
||||||
|
pub cpu_usage: f32,
|
||||||
|
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
impl ProcessSnapshot {
|
||||||
|
pub fn cpu_time(&self) -> Duration {
|
||||||
|
Duration::from_millis(self.accumulated_cpu_time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&sysinfo::Process> for ProcessSnapshot {
|
||||||
|
fn from(value: &sysinfo::Process) -> Self {
|
||||||
|
Self {
|
||||||
|
pid: value.pid().into(),
|
||||||
|
accumulated_cpu_time: value.accumulated_cpu_time(),
|
||||||
|
cpu_usage: value.cpu_usage(),
|
||||||
|
|
||||||
|
name: value.name().to_string_lossy().into_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue