feat: implement collapsible tree view with inclusive resource metrics and improved memory calculation
This commit is contained in:
@@ -3,17 +3,17 @@ name = "syspulse-rs"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "A professional Linux system profiler"
|
description = "A professional Linux system profiler"
|
||||||
authors = ["narl"]
|
authors = ["narl"]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "2.5.5" }
|
tauri-build = { version = "2.5.5" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "2.10.2", features = [] }
|
chrono = "0.4.43"
|
||||||
|
env_logger = "0.11.9"
|
||||||
|
log = "0.4.29"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
sysinfo = "0.38.2"
|
sysinfo = "0.38.2"
|
||||||
chrono = "0.4.43"
|
tauri = "2.10.2"
|
||||||
tokio = { version = "1.49.0", features = ["full"] }
|
tokio = { version = "1.49.0", features = ["full"] }
|
||||||
log = "0.4.29"
|
|
||||||
env_logger = "0.11.9"
|
|
||||||
|
|||||||
@@ -241,7 +241,6 @@ fn stop_profiling(state: State<AppState>) -> Report {
|
|||||||
// 2. Aggregate RAW stats per PID
|
// 2. Aggregate RAW stats per PID
|
||||||
struct PidStats {
|
struct PidStats {
|
||||||
name: String,
|
name: String,
|
||||||
parent_pid: Option<u32>,
|
|
||||||
history: Vec<ProcessHistoryPoint>,
|
history: Vec<ProcessHistoryPoint>,
|
||||||
peak_cpu: f32,
|
peak_cpu: f32,
|
||||||
peak_mem: f32,
|
peak_mem: f32,
|
||||||
@@ -256,7 +255,6 @@ fn stop_profiling(state: State<AppState>) -> Report {
|
|||||||
for proc in &snapshot.processes {
|
for proc in &snapshot.processes {
|
||||||
let entry = pid_map.entry(proc.pid).or_insert_with(|| PidStats {
|
let entry = pid_map.entry(proc.pid).or_insert_with(|| PidStats {
|
||||||
name: proc.name.clone(),
|
name: proc.name.clone(),
|
||||||
parent_pid: proc.parent_pid,
|
|
||||||
history: Vec::new(),
|
history: Vec::new(),
|
||||||
peak_cpu: 0.0,
|
peak_cpu: 0.0,
|
||||||
peak_mem: 0.0,
|
peak_mem: 0.0,
|
||||||
@@ -320,7 +318,7 @@ fn stop_profiling(state: State<AppState>) -> Report {
|
|||||||
|
|
||||||
let pids: Vec<u32> = nodes.keys().cloned().collect();
|
let pids: Vec<u32> = nodes.keys().cloned().collect();
|
||||||
for pid in pids {
|
for pid in pids {
|
||||||
if let Some(&ppid) = child_to_parent.get(&pid) {
|
if let Some(&_ppid) = child_to_parent.get(&pid) {
|
||||||
// Already handled in recursive aggregation or linked below
|
// Already handled in recursive aggregation or linked below
|
||||||
} else {
|
} else {
|
||||||
root_pids.push(pid);
|
root_pids.push(pid);
|
||||||
@@ -328,23 +326,24 @@ fn stop_profiling(state: State<AppState>) -> Report {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. Recursive function to calculate inclusive stats and build tree
|
// 5. Recursive function to calculate inclusive stats and build tree
|
||||||
fn build_node(pid: u32, nodes: &mut HashMap<u32, AggregatedProcess>, child_map: &HashMap<u32, Vec<u32>>) -> AggregatedProcess {
|
fn build_node(pid: u32, nodes: &mut HashMap<u32, AggregatedProcess>, child_map: &HashMap<u32, Vec<u32>>) -> Option<AggregatedProcess> {
|
||||||
let mut node = nodes.remove(&pid).unwrap();
|
let mut node = nodes.remove(&pid)?;
|
||||||
let children_pids = child_map.get(&pid).cloned().unwrap_or_default();
|
let children_pids = child_map.get(&pid).cloned().unwrap_or_default();
|
||||||
|
|
||||||
let mut inc_cpu = node.avg_cpu;
|
let mut inc_cpu = node.avg_cpu;
|
||||||
let mut inc_mem = node.avg_memory_mb;
|
let mut inc_mem = node.avg_memory_mb;
|
||||||
|
|
||||||
for c_pid in children_pids {
|
for c_pid in children_pids {
|
||||||
let child_node = build_node(c_pid, nodes, child_map);
|
if let Some(child_node) = build_node(c_pid, nodes, child_map) {
|
||||||
inc_cpu += child_node.inclusive_avg_cpu;
|
inc_cpu += child_node.inclusive_avg_cpu;
|
||||||
inc_mem += child_node.inclusive_avg_memory_mb;
|
inc_mem += child_node.inclusive_avg_memory_mb;
|
||||||
node.children.push(child_node);
|
node.children.push(child_node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.inclusive_avg_cpu = inc_cpu;
|
node.inclusive_avg_cpu = inc_cpu;
|
||||||
node.inclusive_avg_memory_mb = inc_mem;
|
node.inclusive_avg_memory_mb = inc_mem;
|
||||||
node
|
Some(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut child_map: HashMap<u32, Vec<u32>> = HashMap::new();
|
let mut child_map: HashMap<u32, Vec<u32>> = HashMap::new();
|
||||||
@@ -354,8 +353,16 @@ fn stop_profiling(state: State<AppState>) -> Report {
|
|||||||
|
|
||||||
let mut final_roots = Vec::new();
|
let mut final_roots = Vec::new();
|
||||||
for pid in root_pids {
|
for pid in root_pids {
|
||||||
if nodes.contains_key(&pid) {
|
if let Some(root_node) = build_node(pid, &mut nodes, &child_map) {
|
||||||
final_roots.push(build_node(pid, &mut nodes, &child_map));
|
final_roots.push(root_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include any remaining orphan nodes as roots (e.g. if parent info was missing in snapshots)
|
||||||
|
let remaining_pids: Vec<u32> = nodes.keys().cloned().collect();
|
||||||
|
for pid in remaining_pids {
|
||||||
|
if let Some(node) = build_node(pid, &mut nodes, &child_map) {
|
||||||
|
final_roots.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user