fix: massive performance optimization for PSS collection and system monitoring

This commit is contained in:
2026-02-23 01:26:47 +01:00
parent 191aa494db
commit 47452d9330

View File

@@ -3,12 +3,12 @@
windows_subsystem = "windows" windows_subsystem = "windows"
)] )]
use sysinfo::System; use sysinfo::{System, Pid};
use std::sync::Mutex; use std::sync::Mutex;
use std::process::Command; use std::process::Command;
use tauri::State; use tauri::State;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use std::fs; use std::fs;
use rayon::prelude::*; use rayon::prelude::*;
@@ -119,27 +119,18 @@ fn get_pss(pid: u32) -> Option<u64> {
// --- Commands --- // --- Commands ---
fn get_all_descendants(target_pid: u32, sys: &System) -> HashSet<u32> { fn is_syspulse_recursive(pid: u32, self_pid: u32, sys: &System) -> bool {
let mut descendants = HashSet::new(); if pid == self_pid { return true; }
let mut stack = vec![target_pid]; let mut current = sys.process(Pid::from_u32(pid));
while let Some(proc) = current {
let mut child_map: HashMap<u32, Vec<u32>> = HashMap::new(); if let Some(ppid) = proc.parent() {
for (pid, process) in sys.processes() { if ppid.as_u32() == self_pid { return true; }
if let Some(parent) = process.parent() { current = sys.process(ppid);
child_map.entry(parent.as_u32()).or_default().push(pid.as_u32()); } else {
break;
} }
} }
false
while let Some(pid) = stack.pop() {
if let Some(children) = child_map.get(&pid) {
for &child in children {
if descendants.insert(child) {
stack.push(child);
}
}
}
}
descendants
} }
#[tauri::command] #[tauri::command]
@@ -159,34 +150,29 @@ fn get_system_stats(
let total_memory = sys.total_memory(); let total_memory = sys.total_memory();
let used_memory = sys.used_memory(); let used_memory = sys.used_memory();
let syspulse_set = get_all_descendants(self_pid, &sys); let processes: Vec<ProcessStats> = sys.processes().iter()
.par_bridge()
.filter_map(|(pid, p)| {
let rss = p.memory();
if rss == 0 { return None; }
let raw_processes: Vec<_> = sys.processes().iter() let pid_u32 = pid.as_u32();
.map(|(pid, p)| ( let memory = if rss > 10 * 1024 * 1024 {
pid.as_u32(), get_pss(pid_u32).unwrap_or(rss)
p.parent().map(|pp| pp.as_u32()), } else {
p.name().to_string_lossy().to_string(), rss
p.cpu_usage(), };
p.memory(),
format!("{:?}", p.status()),
p.user_id().map(|u| u.to_string())
))
.collect();
let processes: Vec<ProcessStats> = raw_processes.into_par_iter() Some(ProcessStats {
.map(|(pid, parent_pid, name, cpu, rss, status, uid)| { pid: pid_u32,
let is_syspulse = pid == self_pid || syspulse_set.contains(&pid); parent_pid: p.parent().map(|pp| pp.as_u32()),
let memory = get_pss(pid).unwrap_or(rss); name: p.name().to_string_lossy().to_string(),
ProcessStats { cpu_usage: p.cpu_usage(),
pid,
parent_pid,
name,
cpu_usage: cpu,
memory, memory,
status, status: format!("{:?}", p.status()),
user_id: uid, user_id: p.user_id().map(|u| u.to_string()),
is_syspulse, is_syspulse: is_syspulse_recursive(pid_u32, self_pid, &sys),
} })
}).collect(); }).collect();
if profiling.is_active { if profiling.is_active {
@@ -204,17 +190,15 @@ fn get_system_stats(
0 0
}; };
let mut display_processes = if minimal && !profiling.is_active { let display_processes = if minimal && !profiling.is_active {
Vec::new() Vec::new()
} else { } else {
processes.clone() let mut p = processes.clone();
p.sort_by(|a, b| b.cpu_usage.partial_cmp(&a.cpu_usage).unwrap_or(std::cmp::Ordering::Equal));
p.truncate(50);
p
}; };
if !minimal {
display_processes.sort_by(|a, b| b.cpu_usage.partial_cmp(&a.cpu_usage).unwrap_or(std::cmp::Ordering::Equal));
display_processes.truncate(50);
}
SystemStats { SystemStats {
cpu_usage, cpu_usage,
total_memory, total_memory,
@@ -250,7 +234,6 @@ fn stop_profiling(state: State<AppState>) -> Report {
let end = Utc::now(); let end = Utc::now();
let duration = (end - start).num_seconds(); let duration = (end - start).num_seconds();
// 1. Generate Session Timeline
let timeline: Vec<TimelinePoint> = profiling.snapshots.iter().map(|s| { let timeline: Vec<TimelinePoint> = profiling.snapshots.iter().map(|s| {
let avg_cpu = s.cpu_usage.iter().sum::<f32>() / s.cpu_usage.len() as f32; let avg_cpu = s.cpu_usage.iter().sum::<f32>() / s.cpu_usage.len() as f32;
TimelinePoint { TimelinePoint {
@@ -260,7 +243,6 @@ fn stop_profiling(state: State<AppState>) -> Report {
} }
}).collect(); }).collect();
// 2. Aggregate RAW stats per PID
struct PidStats { struct PidStats {
name: String, name: String,
history: Vec<ProcessHistoryPoint>, history: Vec<ProcessHistoryPoint>,
@@ -297,7 +279,6 @@ fn stop_profiling(state: State<AppState>) -> Report {
} }
} }
// 3. Convert to nodes
let mut nodes: HashMap<u32, AggregatedProcess> = pid_map.into_iter().map(|(pid, stats)| { let mut nodes: HashMap<u32, AggregatedProcess> = pid_map.into_iter().map(|(pid, stats)| {
let total_cpu: f32 = stats.history.iter().map(|h| h.cpu_usage).sum(); let total_cpu: f32 = stats.history.iter().map(|h| h.cpu_usage).sum();
let total_mem: f32 = stats.history.iter().map(|h| h.memory_mb).sum(); let total_mem: f32 = stats.history.iter().map(|h| h.memory_mb).sum();
@@ -323,7 +304,6 @@ fn stop_profiling(state: State<AppState>) -> Report {
}) })
}).collect(); }).collect();
// 4. Build Tree
let mut child_to_parent = HashMap::new(); let mut child_to_parent = HashMap::new();
for snapshot in &profiling.snapshots { for snapshot in &profiling.snapshots {
for proc in &snapshot.processes { for proc in &snapshot.processes {