Skip to main content

Mountain/Binary/IPC/ProcessCommand/
process_get_memory_info.rs

1//! Tauri command - return process memory in `{ private, shared,
2//! residentSet }` form (bytes). Per-platform: `ps` on macOS, `tasklist`
3//! on Windows, `/proc/self/statm` on Linux. Errors fall back to zero
4//! triple so the renderer keeps working in the rare case the platform
5//! probe fails.
6
7use serde_json::{Value, json};
8
9#[tauri::command]
10pub async fn process_get_memory_info() -> Result<Value, String> {
11	#[cfg(target_os = "macos")]
12	{
13		let Output = std::process::Command::new("ps")
14			.args(["-o", "rss=,vsz=", "-p", &std::process::id().to_string()])
15			.output();
16
17		match Output {
18			Ok(Out) => {
19				let Text = String::from_utf8_lossy(&Out.stdout);
20
21				let Parts:Vec<&str> = Text.split_whitespace().collect();
22
23				let Rss = Parts.first().and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * 1024;
24
25				let _Vsz = Parts.get(1).and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * 1024;
26
27				Ok(json!({ "private": Rss, "shared": 0, "residentSet": Rss }))
28			},
29
30			Err(_) => Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 })),
31		}
32	}
33
34	#[cfg(target_os = "windows")]
35	{
36		let Output = std::process::Command::new("tasklist")
37			.args(["/FI", &format!("PID eq {}", std::process::id()), "/FO", "CSV", "/NH"])
38			.output();
39
40		match Output {
41			Ok(Out) => {
42				let Text = String::from_utf8_lossy(&Out.stdout);
43
44				let MemStr = Text.split(',').nth(4).unwrap_or("\"0 K\"");
45
46				let MemKb:u64 = MemStr
47					.chars()
48					.filter(|C| C.is_ascii_digit())
49					.collect::<String>()
50					.parse()
51					.unwrap_or(0);
52
53				let MemBytes = MemKb * 1024;
54
55				Ok(json!({ "private": MemBytes, "shared": 0, "residentSet": MemBytes }))
56			},
57
58			Err(_) => Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 })),
59		}
60	}
61
62	#[cfg(target_os = "linux")]
63	{
64		match tokio::fs::read_to_string("/proc/self/statm").await {
65			Ok(Content) => {
66				let Parts:Vec<&str> = Content.split_whitespace().collect();
67
68				let PageSize:u64 = 4096;
69
70				let _Vsz = Parts.first().and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * PageSize;
71
72				let Rss = Parts.get(1).and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * PageSize;
73
74				let Shared = Parts.get(2).and_then(|V| V.parse::<u64>().ok()).unwrap_or(0) * PageSize;
75
76				Ok(json!({
77					"private": Rss.saturating_sub(Shared),
78					"shared": Shared,
79					"residentSet": Rss
80				}))
81			},
82
83			Err(_) => Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 })),
84		}
85	}
86
87	#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
88	{
89		Ok(json!({ "private": 0, "shared": 0, "residentSet": 0 }))
90	}
91}