fix: massive performance optimization for PSS collection and system monitoring
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user