diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 1cdb3d8..c4b2271 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -5,11 +5,9 @@ mod models; mod monitor; -mod commands; // We'll keep this but gut it mod cli; -use tauri::{State, Manager}; -use std::sync::Mutex; +use tauri::State; use crate::monitor::Monitor; use crate::models::GlobalStats; diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index 8147cd9..bae8ab9 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -1,14 +1,13 @@ -use serde::{Serialize, Deserialize}; -use std::collections::HashMap; +use serde::Serialize; #[derive(Clone, Serialize, Debug)] pub struct ProcessNode { pub pid: u32, pub name: String, - pub cpu_self: f32, // CPU usage of this specific process - pub cpu_children: f32, // Sum of children's CPU (recursive) - pub mem_rss: u64, // Resident Set Size (Self) - pub mem_children: u64, // Sum of children's Mem + pub cpu_self: f32, + pub cpu_children: f32, + pub mem_rss: u64, + pub mem_children: u64, pub children: Vec, } @@ -27,12 +26,6 @@ pub struct GlobalStats { pub cpu_total: f32, pub mem_used: u64, pub mem_total: u64, - pub process_tree: Vec, // Top-level roots (e.g. systemd/init or orphans) + pub process_tree: Vec, pub process_count: usize, } - -#[derive(Clone, Copy, PartialEq)] -pub enum MemoryMode { - Rss, // Fast, default for monitoring - Pss, // Slow, accurate for profiling -} diff --git a/src-tauri/src/monitor.rs b/src-tauri/src/monitor.rs index ec1bf04..0066d1a 100644 --- a/src-tauri/src/monitor.rs +++ b/src-tauri/src/monitor.rs @@ -1,8 +1,8 @@ -use sysinfo::System; +use sysinfo::{System, SystemExt, ProcessExt, CpuExt, PidExt}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use crate::models::*; pub struct Monitor { @@ -39,8 +39,6 @@ impl Monitor { thread::spawn(move || { let mut sys = System::new_all(); - - // Initial wait to let sysinfo calculate CPU diff thread::sleep(Duration::from_millis(500)); sys.refresh_all(); @@ -49,21 +47,17 @@ impl Monitor { break; } - // 1. Refresh System State (Efficiently) sys.refresh_cpu_all(); sys.refresh_memory(); sys.refresh_processes(sysinfo::ProcessesToUpdate::All, true); - // 2. Calculate Global Stats let cpu_total = sys.global_cpu_usage(); let mem_used = sys.used_memory(); let mem_total = sys.total_memory(); let process_count = sys.processes().len(); - // 3. Build Process Tree let tree = build_process_tree(&sys); - // 4. Update Shared State { let mut lock = data_ref.lock().unwrap(); lock.cpu_total = cpu_total; @@ -73,19 +67,13 @@ impl Monitor { lock.process_count = process_count; } - // 5. Sleep (Aim for 1s interval) thread::sleep(Duration::from_secs(1)); } }); } - - pub fn stop(&self) { - *self.running.lock().unwrap() = false; - } } fn build_process_tree(sys: &System) -> Vec { - // 1. Collect all raw nodes let mut raw_nodes: HashMap = HashMap::new(); let mut ppid_map: HashMap = HashMap::new(); @@ -107,19 +95,16 @@ fn build_process_tree(sys: &System) -> Vec { } } - // 2. Build Hierarchy (Bottom-Up or Map-Based) let mut children_map: HashMap> = HashMap::new(); for (child, parent) in &ppid_map { children_map.entry(*parent).or_default().push(*child); } - // Identify roots let roots: Vec = raw_nodes.keys() - .filter(|pid| !ppid_map.contains_key(pid)) // Has no parent in the list + .filter(|pid| !ppid_map.contains_key(pid)) .cloned() .collect(); - // 3. Recursive Tree Builder fn build_recursive( pid: u32, nodes_map: &mut HashMap, @@ -136,7 +121,6 @@ fn build_process_tree(sys: &System) -> Vec { } } - // Sort children by Mem impact by default node.children.sort_by(|a, b| b.total_mem().cmp(&a.total_mem())); Some(node) @@ -152,7 +136,6 @@ fn build_process_tree(sys: &System) -> Vec { } } - // Sort roots by total CPU tree.sort_by(|a, b| b.total_cpu().partial_cmp(&a.total_cpu()).unwrap_or(std::cmp::Ordering::Equal)); tree diff --git a/src/App.tsx b/src/App.tsx index 112545b..dfd7093 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,57 +1,31 @@ import { useState, useEffect } from 'react'; import { invoke } from '@tauri-apps/api/core'; -import { SystemStats, ProfilingReport } from './types'; +import { GlobalStats } from './types'; import { Dashboard } from './components/Dashboard'; -import { ReportView } from './components/ReportView'; function App() { - const [view, setView] = useState<'dashboard' | 'report'>('dashboard'); - const [stats, setStats] = useState(null); + const [stats, setStats] = useState(null); const [history, setHistory] = useState<{ time: string; cpu: number }[]>([]); - const [report, setReport] = useState(null); - // Initial report check - useEffect(() => { - const checkInitialReport = async () => { - try { - const data = await invoke('get_initial_report'); - if (data) { - setReport(data); - setView('report'); - } - } catch (e) { - console.error('Failed to get initial report:', e); - } - }; - checkInitialReport(); - }, []); - - // Stats Polling useEffect(() => { let timeoutId: number; let isMounted = true; const fetchStats = async () => { - if (view !== 'dashboard' && !stats?.is_recording) return; - try { - const data = await invoke('get_system_stats', { - minimal: (stats?.is_recording || view === 'report') - }); + const data = await invoke('get_latest_stats'); if (!isMounted) return; setStats(data); - const avgCpu = data.cpu_usage.reduce((a, b) => a + b, 0) / data.cpu_usage.length; - setHistory(prev => { - const newHistory = [...prev, { time: new Date().toLocaleTimeString(), cpu: avgCpu }]; + const newHistory = [...prev, { time: new Date().toLocaleTimeString(), cpu: data.cpu_total }]; if (newHistory.length > 60) newHistory.shift(); return newHistory; }); } catch (e) { - console.error(e); + console.error('Failed to fetch stats:', e); } finally { if (isMounted) { timeoutId = window.setTimeout(fetchStats, 1000); @@ -64,38 +38,21 @@ function App() { isMounted = false; clearTimeout(timeoutId); }; - }, [view, stats?.is_recording]); + }, []); - const toggleRecording = async () => { - if (stats?.is_recording) { - const reportData = await invoke('stop_profiling'); - setReport(reportData); - setView('report'); - } else { - await invoke('start_profiling'); - } - }; - - if (view === 'report' && report) { - return ( - setView('dashboard')} - /> - ); - } - - if (!stats) return
Initializing SysPulse...
; + if (!stats) return ( +
+ Initializing SysPulse +
+
+
+
+ ); return ( { - setReport(importedReport); - setView('report'); - }} /> ); } diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index 2ea5d21..e7a8529 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -1,61 +1,89 @@ -import { useState } from 'react'; +import { useState, useMemo, Fragment } from 'react'; import { - Activity, Cpu, Server, Database, Play, Square, Shield, Target, Download + Activity, Cpu, Server, Database, Shield, ChevronRight, ChevronDown, Search } from 'lucide-react'; import { AreaChart, Area, ResponsiveContainer } from 'recharts'; -import { invoke } from '@tauri-apps/api/core'; -import { SystemStats, ProfilingReport } from '../types'; -import { cn, formatBytes, formatDuration } from '../utils'; +import { GlobalStats, ProcessNode } from '../types'; +import { cn, formatBytes } from '../utils'; interface Props { - stats: SystemStats; + stats: GlobalStats; history: { time: string; cpu: number }[]; - onRecordingToggle: () => void; - onImport: (report: ProfilingReport) => void; } -export function Dashboard({ stats, history, onRecordingToggle, onImport }: Props) { +export function Dashboard({ stats, history }: Props) { const [searchTerm, setSearchBar] = useState(""); - const [pinnedPid, setPinnedPid] = useState(null); + const [expandedPids, setExpandedPids] = useState>(new Set()); - const avgCpu = stats.cpu_usage.reduce((a, b) => a + b, 0) / stats.cpu_usage.length; - const memoryPercent = (stats.used_memory / stats.total_memory) * 100; + const memoryPercent = (Number(stats.mem_used) / Number(stats.mem_total)) * 100; - const filteredLiveProcs = stats.processes.filter(p => - p.name.toLowerCase().includes(searchTerm.toLowerCase()) || - p.pid.toString().includes(searchTerm) - ); - - const startTargeted = async (pid: number) => { - await invoke('start_targeted_profiling', { pid }); + const toggleExpand = (pid: number) => { + const next = new Set(expandedPids); + if (next.has(pid)) next.delete(pid); + else next.add(pid); + setExpandedPids(next); }; - const killProcess = async (pid: number) => { - try { - await invoke('run_as_admin', { command: `kill -9 ${pid}` }); - } catch (e) { - alert(`Failed to kill process: ${e}`); - } - }; - - const handleImport = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (!file) return; - - const reader = new FileReader(); - reader.onload = (event) => { - try { - const data = JSON.parse(event.target?.result as string) as ProfilingReport; - if (data.aggregated_processes && data.timeline) { - onImport(data); - } else { - alert('Invalid report format'); + // Flatten the tree for the list view if searching, or keep it hierarchical + const filteredTree = useMemo(() => { + if (!searchTerm) return stats.process_tree; + + const search = searchTerm.toLowerCase(); + const result: ProcessNode[] = []; + + function searchRecursive(nodes: ProcessNode[]) { + for (const node of nodes) { + if (node.name.toLowerCase().includes(search) || node.pid.toString().includes(search)) { + result.push(node); } - } catch (err) { - alert('Failed to parse JSON'); + searchRecursive(node.children); } - }; - reader.readAsText(file); + } + + searchRecursive(stats.process_tree); + return result; + }, [stats.process_tree, searchTerm]); + + const renderProcessNode = (node: ProcessNode, depth = 0) => { + const isExpanded = expandedPids.has(node.pid); + const hasChildren = node.children.length > 0; + const totalCpu = node.cpu_self + node.cpu_children; + const totalMem = node.mem_rss + node.mem_children; + + return ( + +
0 && "bg-base/10" + )} + > +
+ {hasChildren && !searchTerm ? ( + + ) :
} + {node.name} +
+
{node.pid}
+
+ {totalCpu.toFixed(1)}% + {depth === 0 && node.cpu_children > 0 && Self: {node.cpu_self.toFixed(1)}%} +
+
+ {formatBytes(totalMem)} + {depth === 0 && node.mem_children > 0 && Self: {formatBytes(node.mem_rss)}} +
+
+ +
+
+ {hasChildren && isExpanded && !searchTerm && node.children.map(child => renderProcessNode(child, depth + 1))} + + ); }; return ( @@ -68,188 +96,97 @@ export function Dashboard({ stats, history, onRecordingToggle, onImport }: Props SysPulse
- -
- +
+
+ Live Monitor +
- {stats.is_recording ? ( -
-
-
-
-
- -
-
-
-

Profiling Active

-

{formatDuration(stats.recording_duration)}

-
-
-
-
Global CPU
-
{avgCpu.toFixed(1)}%
-
-
-
Global RAM
-
{memoryPercent.toFixed(1)}%
-
-
-
- - Performance optimized snapshot mode enabled -
+
+
+
System Load
+
+ {stats.cpu_total.toFixed(1)} + %
- ) : ( - <> -
-
-
CPU Load
-
- {avgCpu.toFixed(1)} - % -
-
- - - - - - - - - - - -
-
+
+ + + + + + + + + + + +
+
-
-
Memory
-
- {formatBytes(stats.used_memory)} - used -
-
-
- {memoryPercent.toFixed(1)}% Utilized - {formatBytes(stats.total_memory, 0)} Total -
-
-
-
-
-
+
+
Memory
+
+ {formatBytes(stats.mem_used)} + used +
+
+
+ {memoryPercent.toFixed(1)}% Utilized + {formatBytes(stats.mem_total, 0)} Total +
+
+
+
+
+
-
-
Tasks
-
- {stats.processes.length} - Processes -
-
- Live system feed. Target a process to profile its hierarchy in detail. -
-
-
+
+
Process Stack
+
+ {stats.process_count} + Active +
+
+ Deep hierarchical tracking enabled. Child process overhead is summed into parent totals. +
+
+
-
-
-

- - Live Feed -

-
-
- setSearchBar(e.target.value)} - className="bg-surface1/50 border border-surface2 rounded-xl px-4 py-2 text-xs font-bold text-text placeholder:text-overlay1 focus:outline-none focus:ring-2 focus:ring-blue/30 w-64 transition-all" - /> -
-
-
- Real-time -
-
-
- -
-
Process
-
PID
-
CPU %
-
Memory
-
Actions
-
- -
- {filteredLiveProcs.map((proc) => ( -
setPinnedPid(pinnedPid === proc.pid ? null : proc.pid)} - > -
-
- {proc.name} -
-
{proc.pid}
-
{proc.cpu_usage.toFixed(1)}%
-
{formatBytes(proc.memory, 0)}
-
- - -
-
- ))} -
-
- - )} +
+
+

+ + System Hierarchy +

+
+
+ + setSearchBar(e.target.value)} + className="bg-surface1/50 border border-surface2 rounded-xl pl-9 pr-4 py-2 text-xs font-bold text-text placeholder:text-overlay1 focus:outline-none focus:ring-2 focus:ring-blue/30 w-64 transition-all" + /> +
+
+
+ +
+
Hierarchy
+
PID
+
Total CPU
+
Total RAM
+
Action
+
+ +
+ {filteredTree.map(node => renderProcessNode(node))} +
+
); diff --git a/src/components/ProcessInspector.tsx b/src/components/ProcessInspector.tsx deleted file mode 100644 index ce0c6a9..0000000 --- a/src/components/ProcessInspector.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { X, AlertTriangle, CheckSquare } from 'lucide-react'; -import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid } from 'recharts'; -import { AggregatedProcess, ProfilingMode } from '../types'; -import { formatMB } from '../utils'; - -interface Props { - selectedProcess: AggregatedProcess; - mode: ProfilingMode; - onClose: () => void; -} - -export function ProcessInspector({ selectedProcess, mode, onClose }: Props) { - return ( -
-
-
-
-
- {mode === ProfilingMode.Targeted ? `Process Inspector (PID: ${selectedProcess.pid})` : "Application Cluster Inspector"} -
-

{selectedProcess.name}

-
- -
- -
-
-
-
Total Avg CPU
-
- {(mode === ProfilingMode.Targeted ? selectedProcess.inclusive_avg_cpu : selectedProcess.avg_cpu).toFixed(1)}% -
-

Combined impact of this application.

-
-
-
Total Avg RAM
-
- {formatMB(mode === ProfilingMode.Targeted ? selectedProcess.inclusive_avg_memory_mb : selectedProcess.avg_memory_mb)} -
-

Proportional memory footprint.

-
-
- -
-
Resource History (Summed)
-
- - - - - - - - - - - - - - - - { - if (name === 'memory_mb') return [formatMB(value), 'RAM']; - if (name === 'cpu_usage') return [`${value.toFixed(1)}%`, 'CPU']; - return [value, name]; - }} - /> - - - - -
-
- -
-

Profiling Details

-
-
- Peak Recorded Load - {selectedProcess.peak_cpu.toFixed(1)}% -
-
- Peak Recorded RAM - {formatMB(selectedProcess.peak_memory_mb)} -
-
- - {mode === ProfilingMode.Targeted ? "Child Process Count" : "Active Instances Count"} - - - {mode === ProfilingMode.Targeted ? selectedProcess.children.length : selectedProcess.instance_count} - -
-
-
- -
-

Profiling Insights

-
- {selectedProcess.warnings.length > 0 ? selectedProcess.warnings.map((w, idx) => ( -
- - {w} -
- )) : ( -
- - Healthy Performance Profile -
- )} -
-
-
-
-
- ); -} diff --git a/src/components/ReportView.tsx b/src/components/ReportView.tsx deleted file mode 100644 index 5935d1f..0000000 --- a/src/components/ReportView.tsx +++ /dev/null @@ -1,336 +0,0 @@ -import React, { useState, useMemo, Fragment } from 'react'; -import { - Activity, Server, Play, AlertTriangle, ArrowLeft, Shield, Save, Eye, EyeOff -} from 'lucide-react'; -import { - AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid -} from 'recharts'; -import { invoke } from '@tauri-apps/api/core'; -import { AggregatedProcess, ProfilingMode, ProfilingReport } from '../types'; -import { cn, formatBytes, formatMB, formatDuration } from '../utils'; -import { ProcessInspector } from './ProcessInspector'; - -interface Props { - report: ProfilingReport; - onBack: () => void; -} - -type SortField = 'name' | 'pid' | 'inclusive_avg_cpu' | 'peak_cpu' | 'inclusive_avg_memory_mb' | 'peak_memory_mb' | 'avg_cpu' | 'avg_memory_mb'; - -export function ReportView({ report, onBack }: Props) { - const [sortField, setSortField] = useState(report.mode === ProfilingMode.Targeted ? 'inclusive_avg_cpu' : 'avg_cpu'); - const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); - const [selectedProcess, setSelectedProcess] = useState(null); - const [hideProfiler, setHideProfiler] = useState(true); - const [expandedNodes, setExpandedNodes] = useState>(new Set()); - - const toggleExpand = (pid: number) => { - const newExpanded = new Set(expandedNodes); - if (newExpanded.has(pid)) newExpanded.delete(pid); - else newExpanded.add(pid); - setExpandedNodes(newExpanded); - }; - - const handleSort = (field: SortField) => { - if (sortField === field) { - setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); - } else { - setSortField(field); - setSortOrder('desc'); - } - }; - - const filteredProcesses = useMemo(() => { - return report.aggregated_processes.filter(p => !hideProfiler || !p.is_syspulse); - }, [report, hideProfiler]); - - const sortedProcesses = useMemo(() => { - return [...filteredProcesses] - .sort((a, b) => { - const valA = a[sortField as keyof AggregatedProcess]; - const valB = b[sortField as keyof AggregatedProcess]; - - if (typeof valA === 'string' && typeof valB === 'string') { - return sortOrder === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA); - } - - const numA = (valA as number) ?? 0; - const numB = (valB as number) ?? 0; - - return sortOrder === 'asc' ? numA - numB : numB - numA; - }); - }, [filteredProcesses, sortField, sortOrder]); - - const reactiveTimeline = useMemo(() => { - return report.timeline.map(p => ({ - ...p, - cpu: hideProfiler ? (p.cpu_total - p.cpu_profiler) : p.cpu_total, - mem: hideProfiler ? (p.mem_total_gb - p.mem_profiler_gb) : p.mem_total_gb - })); - }, [report, hideProfiler]); - - const summaryStats = useMemo(() => { - if (report.mode === ProfilingMode.Targeted) { - const root = sortedProcesses[0]; - if (root) { - return { cpu: root.inclusive_avg_cpu, mem: root.inclusive_avg_memory_mb }; - } - } - const totalCpu = sortedProcesses.reduce((acc, p) => acc + p.avg_cpu, 0); - const totalMem = sortedProcesses.reduce((acc, p) => acc + p.avg_memory_mb, 0); - return { cpu: totalCpu, mem: totalMem }; - }, [sortedProcesses, report.mode]); - - const saveReport = async () => { - try { - const path = await invoke('save_report', { report }); - alert(`Report saved to: ${path}`); - } catch (e) { - alert(`Failed to save: ${e}`); - } - }; - - const renderTreeRows = (nodes: AggregatedProcess[], depth = 0): React.ReactNode => { - return nodes.map((proc) => { - const isExpanded = expandedNodes.has(proc.pid); - const hasChildren = proc.children && proc.children.length > 0; - - return ( - -
{ - e.stopPropagation(); - setSelectedProcess(proc); - }} - > -
- {hasChildren ? ( - - ) : ( -
- )} -
- {proc.name} -
- -
{proc.pid}
- -
- {proc.inclusive_avg_cpu.toFixed(1)}% - {proc.children.length > 0 && ({proc.avg_cpu.toFixed(1)}% self)} -
- -
{proc.peak_cpu.toFixed(1)}%
- -
- {formatMB(proc.inclusive_avg_memory_mb)} - {proc.children.length > 0 && ({formatMB(proc.avg_memory_mb)} self)} -
- -
{formatMB(proc.peak_memory_mb, 0)}
- -
- {proc.warnings.length > 0 ? proc.warnings.map((w, idx) => ( - - {w} - - )) : ( - proc.children.length > 0 ? {proc.children.length} units : null - )} -
-
- {hasChildren && isExpanded && renderTreeRows( - proc.children.filter(c => !hideProfiler || !c.is_syspulse), - depth + 1 - )} - - ); - }); - }; - - return ( -
-
-
-
- -
- - {report.mode === ProfilingMode.Targeted ? `Target: ${report.target_name || "Process"}` : "Global Report"} - -
-
- - - -
-
- -
-
-
-
Session Duration
-
{formatDuration(report.duration_seconds)}
-
-
-
Impact Avg CPU
-
{summaryStats.cpu.toFixed(1)}%
-
-
-
Impact Avg RAM
-
{formatMB(summaryStats.mem)}
-
-
-
Issue Alerts
-
- {filteredProcesses.filter(p => p.warnings.length > 0).length} -
-
-
- -
-
-

- {hideProfiler ? "Reactive Analysis Profile (Profiler Hidden)" : "Full System Load Profile"} -

-
-
- - - - - - - - - - - - { - if (name === 'mem') return [formatBytes(value * 1024 * 1024 * 1024), 'RAM']; - if (name === 'cpu') return [`${value.toFixed(1)}%`, 'CPU']; - return [value, name]; - }} - /> - - - - -
-
- -
-
-

- {report.mode === ProfilingMode.Targeted ? "Hierarchical Analysis" : "Aggregated Resource Matrix"} -

-
- {report.mode === ProfilingMode.Targeted && ( -
-
Inclusive Sum -
- )} - - {report.mode === ProfilingMode.Targeted ? "Toggle Nodes to Expand" : "Grouped by Application Name"} - -
-
- -
-
handleSort('name')}> - Process {sortField === 'name' && (sortOrder === 'asc' ? '↑' : '↓')} -
-
handleSort('pid')}> - {report.mode === ProfilingMode.Targeted ? "PID" : "Units"} -
-
handleSort(report.mode === ProfilingMode.Targeted ? 'inclusive_avg_cpu' : 'avg_cpu')}>Avg CPU
-
handleSort('peak_cpu')}>Peak
-
handleSort(report.mode === ProfilingMode.Targeted ? 'inclusive_avg_memory_mb' : 'avg_memory_mb')}>Avg Mem
-
handleSort('peak_memory_mb')}>Peak
-
Insights
-
- -
- {report.mode === ProfilingMode.Targeted ? renderTreeRows(sortedProcesses) : sortedProcesses.map((proc, i) => ( -
setSelectedProcess(proc)} - className="grid grid-cols-[1fr_80px_100px_100px_100px_100px_200px] gap-4 px-4 py-4 border-b border-surface1/20 hover:bg-surface1/20 cursor-pointer transition-all rounded-xl group" - > -
-
- {proc.name} -
-
{proc.instance_count}
-
{proc.avg_cpu.toFixed(1)}%
-
{proc.peak_cpu.toFixed(1)}%
-
{formatMB(proc.avg_memory_mb)}
-
{formatMB(proc.peak_memory_mb, 0)}
-
- {proc.warnings.length > 0 ? proc.warnings.map((w, idx) => ( - - {w} - - )) : ( - Healthy Cluster - )} -
-
- ))} -
- -
- - Real Memory (PSS) used for accuracy. Global mode aggregates processes by application name for performance. -
-
- - {selectedProcess && ( - setSelectedProcess(null)} - /> - )} -
-
- ); -} diff --git a/src/types/index.ts b/src/types/index.ts index 39b35ec..5d16194 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,63 +1,17 @@ -export enum ProfilingMode { - Global = "Global", - Targeted = "Targeted" -} - -export interface ProcessStats { +export interface ProcessNode { pid: number; name: string; - cpu_usage: number; - memory: number; - status: string; - user_id?: string; - is_syspulse: boolean; + cpu_self: number; + cpu_children: number; + mem_rss: number; + mem_children: number; + children: ProcessNode[]; } -export interface SystemStats { - cpu_usage: number[]; - total_memory: number; - used_memory: number; - processes: ProcessStats[]; - is_recording: boolean; - recording_duration: number; -} - -export interface TimelinePoint { - time: string; +export interface GlobalStats { cpu_total: number; - mem_total_gb: number; - cpu_profiler: number; - mem_profiler_gb: number; -} - -export interface ProcessHistoryPoint { - time: string; - cpu_usage: number; - memory_mb: number; -} - -export interface AggregatedProcess { - pid: number; - name: string; - avg_cpu: number; - peak_cpu: number; - avg_memory_mb: number; - peak_memory_mb: number; - inclusive_avg_cpu: number; - inclusive_avg_memory_mb: number; - instance_count: number; - warnings: string[]; - history: ProcessHistoryPoint[]; - is_syspulse: boolean; - children: AggregatedProcess[]; -} - -export interface ProfilingReport { - start_time: string; - end_time: string; - duration_seconds: number; - mode: ProfilingMode; - target_name?: string; - timeline: TimelinePoint[]; - aggregated_processes: AggregatedProcess[]; + mem_used: number; + mem_total: number; + process_tree: ProcessNode[]; + process_count: number; }