From 61fc2abe116a79535708eb94dbb1dc3091c82758 Mon Sep 17 00:00:00 2001 From: dearfl Date: Thu, 11 Apr 2024 15:32:17 +0800 Subject: [PATCH] refact system module --- Cargo.lock | 119 +++++++----- crates/op/host-op-system/Cargo.toml | 2 +- crates/op/host-op-system/src/cpu/host.rs | 10 +- .../src/{interrupts => interrupt}/host.rs | 51 +++--- .../src/{interrupts => interrupt}/irq.rs | 4 +- .../src/{interrupts => interrupt}/mod.rs | 0 .../src/{interrupts => interrupt}/raw.rs | 0 .../src/{interrupts => interrupt}/stat.rs | 4 +- crates/op/host-op-system/src/lib.rs | 27 ++- crates/op/host-op-system/src/memory/host.rs | 53 ++++-- crates/op/host-op-system/src/os/host.rs | 99 ++-------- crates/op/host-op-system/src/os/mod.rs | 1 + crates/op/host-op-system/src/process/host.rs | 172 ++++++++++++++++++ crates/op/host-op-system/src/process/mod.rs | 15 ++ crates/op/host-op-system/src/rps/host.rs | 3 +- examples/wasi/get_processes/src/main.rs | 74 ++++++-- src/psh-sdk-wit | 2 +- 17 files changed, 435 insertions(+), 201 deletions(-) rename crates/op/host-op-system/src/{interrupts => interrupt}/host.rs (52%) rename crates/op/host-op-system/src/{interrupts => interrupt}/irq.rs (97%) rename crates/op/host-op-system/src/{interrupts => interrupt}/mod.rs (100%) rename crates/op/host-op-system/src/{interrupts => interrupt}/raw.rs (100%) rename crates/op/host-op-system/src/{interrupts => interrupt}/stat.rs (99%) create mode 100644 crates/op/host-op-system/src/process/host.rs create mode 100644 crates/op/host-op-system/src/process/mod.rs diff --git a/Cargo.lock b/Cargo.lock index bf81ff5..33790e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,12 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -103,9 +109,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "arbitrary" @@ -273,9 +279,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -368,9 +374,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" dependencies = [ "jobserver", "libc", @@ -391,6 +397,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.4", +] + [[package]] name = "clang-sys" version = "1.7.0" @@ -694,9 +712,9 @@ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -746,6 +764,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -909,9 +937,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06fddc2749e0528d2813f95e050e87e52c8cbbae56223b9babf73b3e53b0cc6" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -999,6 +1027,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "home" version = "0.5.9" @@ -1025,7 +1059,7 @@ version = "0.1.0" dependencies = [ "anyhow", "num_cpus", - "sysinfo", + "procfs", "uname", "wasmtime", "wasmtime-wasi", @@ -1426,12 +1460,12 @@ dependencies = [ ] [[package]] -name = "ntapi" -version = "0.4.1" +name = "num-traits" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ - "winapi", + "autocfg", ] [[package]] @@ -1576,6 +1610,32 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "procfs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +dependencies = [ + "bitflags 2.5.0", + "chrono", + "flate2", + "hex", + "lazy_static", + "procfs-core", + "rustix", +] + +[[package]] +name = "procfs-core" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +dependencies = [ + "bitflags 2.5.0", + "chrono", + "hex", +] + [[package]] name = "prost" version = "0.12.4" @@ -1659,9 +1719,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1946,21 +2006,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "sysinfo" -version = "0.30.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1a378e48fb3ce3a5cf04359c456c9c98ff689bcf1c1bc6e6a31f247686f275" -dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", - "ntapi", - "once_cell", - "rayon", - "windows", -] - [[package]] name = "system-interface" version = "0.26.1" @@ -2918,16 +2963,6 @@ dependencies = [ "wasmtime-environ", ] -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core", - "windows-targets 0.52.4", -] - [[package]] name = "windows-core" version = "0.52.0" diff --git a/crates/op/host-op-system/Cargo.toml b/crates/op/host-op-system/Cargo.toml index b55b7bf..174f4c4 100644 --- a/crates/op/host-op-system/Cargo.toml +++ b/crates/op/host-op-system/Cargo.toml @@ -11,4 +11,4 @@ anyhow = "1.0.80" wasmtime-wasi = "18.0.1" uname = "0.1.1" num_cpus = "1.16.0" -sysinfo = "0.30.7" +procfs = "0.16.0" diff --git a/crates/op/host-op-system/src/cpu/host.rs b/crates/op/host-op-system/src/cpu/host.rs index 4c6bb58..20a2415 100644 --- a/crates/op/host-op-system/src/cpu/host.rs +++ b/crates/op/host-op-system/src/cpu/host.rs @@ -11,6 +11,7 @@ // // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . + use crate::{ profiling::system::cpu::{ self, AddressSizes as GuestAddressSizes, Arm64CpuInfo as GuestArm64CpuInfo, @@ -115,8 +116,11 @@ impl From<&HostCpuInfo> for GuestCpuInfo { } impl cpu::Host for SysCtx { - fn get_cpu_info(&mut self) -> wasmtime::Result> { - let cpu_info = parse_cpuinfo!().unwrap(); - Ok(Ok((&cpu_info).into())) + fn info(&mut self) -> wasmtime::Result> { + let cpu_info = match parse_cpuinfo!() { + Ok(ref info) => Ok(info.into()), + Err(err) => Err(err.to_string()), + }; + Ok(cpu_info) } } diff --git a/crates/op/host-op-system/src/interrupts/host.rs b/crates/op/host-op-system/src/interrupt/host.rs similarity index 52% rename from crates/op/host-op-system/src/interrupts/host.rs rename to crates/op/host-op-system/src/interrupt/host.rs index 463d087..8033970 100644 --- a/crates/op/host-op-system/src/interrupts/host.rs +++ b/crates/op/host-op-system/src/interrupt/host.rs @@ -11,14 +11,15 @@ // // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . + use super::{InterruptDetails, InterruptType, IrqDetails}; -use crate::interrupts::raw::{parse_interrupts, parse_irq}; -use crate::profiling::system::interrupts; +use crate::interrupt::raw::{parse_interrupts, parse_irq}; +use crate::profiling::system::interrupt; use crate::SysCtx; -impl From<&IrqDetails> for interrupts::Irq { +impl From<&IrqDetails> for interrupt::InterruptInfo { fn from(value: &IrqDetails) -> Self { - interrupts::Irq { + Self { number: value.irq_number, smp_affinity: value.smp_affinity.clone(), smp_affinity_list: value.smp_affinity_list.clone(), @@ -27,12 +28,14 @@ impl From<&IrqDetails> for interrupts::Irq { } } -impl From<&InterruptDetails> for interrupts::Stat { +impl From<&InterruptDetails> for interrupt::InterruptStat { fn from(value: &InterruptDetails) -> Self { - interrupts::Stat { + Self { interrupt_type: match &value.interrupt_type { - InterruptType::Common(irq) => interrupts::Kind::Common(*irq), - InterruptType::ArchSpecific(irq) => interrupts::Kind::ArchSpecific(irq.clone()), + InterruptType::Common(irq) => interrupt::InterruptType::Common(*irq), + InterruptType::ArchSpecific(irq) => { + interrupt::InterruptType::ArchSpecific(irq.clone()) + } }, description: value.description.clone(), per_cpu_counts: value.cpu_counts.clone(), @@ -40,24 +43,26 @@ impl From<&InterruptDetails> for interrupts::Stat { } } -impl interrupts::Host for SysCtx { - fn get_interrupts_info(&mut self) -> wasmtime::Result, String>> { - match parse_irq!() { - Ok(irq) => Ok(Ok(irq +impl interrupt::Host for SysCtx { + fn info(&mut self) -> wasmtime::Result, String>> { + let info = match parse_irq!() { + Ok(irq) => Ok(irq .iter() - .map(interrupts::Irq::from) - .collect::>())), - Err(e) => Ok(Err(format!("{}: {}", "get interrupt info failed", e))), - } + .map(interrupt::InterruptInfo::from) + .collect::>()), + Err(e) => Err(format!("{}: {}", "get interrupt info failed", e)), + }; + Ok(info) } - fn get_interrupts_stat(&mut self) -> wasmtime::Result, String>> { - match parse_interrupts!() { - Ok(bindings) => Ok(Ok(bindings + fn stat(&mut self) -> wasmtime::Result, String>> { + let stat = match parse_interrupts!() { + Ok(bindings) => Ok(bindings .iter() - .map(interrupts::Stat::from) - .collect::>())), - Err(e) => Ok(Err(format!("{}: {}", "get interrupt statistics failed", e))), - } + .map(interrupt::InterruptStat::from) + .collect::>()), + Err(e) => Err(format!("{}: {}", "get interrupt statistics failed", e)), + }; + Ok(stat) } } diff --git a/crates/op/host-op-system/src/interrupts/irq.rs b/crates/op/host-op-system/src/interrupt/irq.rs similarity index 97% rename from crates/op/host-op-system/src/interrupts/irq.rs rename to crates/op/host-op-system/src/interrupt/irq.rs index 5d451c7..ae792e9 100644 --- a/crates/op/host-op-system/src/interrupts/irq.rs +++ b/crates/op/host-op-system/src/interrupt/irq.rs @@ -62,10 +62,10 @@ pub fn do_parse_all_irq(path: &str) -> std::io::Result> { macro_rules! parse_irq { ($path:expr) => { - crate::interrupts::irq::do_parse_all_irq($path) + crate::interrupt::irq::do_parse_all_irq($path) }; () => { - crate::interrupts::irq::do_parse_all_irq("/proc/irq") + crate::interrupt::irq::do_parse_all_irq("/proc/irq") }; } diff --git a/crates/op/host-op-system/src/interrupts/mod.rs b/crates/op/host-op-system/src/interrupt/mod.rs similarity index 100% rename from crates/op/host-op-system/src/interrupts/mod.rs rename to crates/op/host-op-system/src/interrupt/mod.rs diff --git a/crates/op/host-op-system/src/interrupts/raw.rs b/crates/op/host-op-system/src/interrupt/raw.rs similarity index 100% rename from crates/op/host-op-system/src/interrupts/raw.rs rename to crates/op/host-op-system/src/interrupt/raw.rs diff --git a/crates/op/host-op-system/src/interrupts/stat.rs b/crates/op/host-op-system/src/interrupt/stat.rs similarity index 99% rename from crates/op/host-op-system/src/interrupts/stat.rs rename to crates/op/host-op-system/src/interrupt/stat.rs index 406a513..b37d305 100644 --- a/crates/op/host-op-system/src/interrupts/stat.rs +++ b/crates/op/host-op-system/src/interrupt/stat.rs @@ -60,10 +60,10 @@ pub fn do_parse_interrupts(path: &str) -> io::Result> { macro_rules! parse_interrupts { ($path:expr) => { - crate::interrupts::stat::do_parse_interrupts($path) + crate::interrupt::stat::do_parse_interrupts($path) }; () => { - crate::interrupts::stat::do_parse_interrupts("/proc/interrupts") + crate::interrupt::stat::do_parse_interrupts("/proc/interrupts") }; } diff --git a/crates/op/host-op-system/src/lib.rs b/crates/op/host-op-system/src/lib.rs index 75dac62..8da2572 100644 --- a/crates/op/host-op-system/src/lib.rs +++ b/crates/op/host-op-system/src/lib.rs @@ -11,30 +11,43 @@ // // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . + mod cpu; -mod interrupts; +mod interrupt; mod memory; mod os; +mod process; mod rps; mod utils; -use wasmtime::component::Linker; +use wasmtime::component::{Linker, ResourceTable}; + +pub use procfs::process::Process; wasmtime::component::bindgen!({ path: "../../../src/psh-sdk-wit/wit/deps/system", world: "imports", + with: { + "profiling:system/process/process": Process, + } }); +#[allow(dead_code)] pub struct SysCtx { - sys: sysinfo::System, + page_size: u64, + boot_time_sec: u64, + tick_per_sec: u64, + table: ResourceTable, } impl Default for SysCtx { fn default() -> Self { - let mut sys = sysinfo::System::new_all(); - std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL); - sys.refresh_all(); - Self { sys } + Self { + page_size: procfs::page_size(), + boot_time_sec: procfs::boot_time_secs().unwrap_or(0), + tick_per_sec: procfs::ticks_per_second(), + table: ResourceTable::default(), + } } } diff --git a/crates/op/host-op-system/src/memory/host.rs b/crates/op/host-op-system/src/memory/host.rs index d5ba986..3fc2f42 100644 --- a/crates/op/host-op-system/src/memory/host.rs +++ b/crates/op/host-op-system/src/memory/host.rs @@ -11,20 +11,21 @@ // // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . + use std::process::Command; use crate::profiling::system::memory::{ - self, MemoryInfo as GuestMemoryInfo, MemoryModule as GuestMemoryModule, + self, MemoryInfo as GuestMemoryInfo, MemoryStat as GuestMemoryStat, }; use super::raw::{parse_meminfo, parse_memory_module}; -use super::{MemInfo as HostMemoryInfo, MemoryModule as HostMemoryModule}; +use super::{MemInfo as HostMemoryStat, MemoryModule as HostMemoryInfo}; use crate::utils::which; use crate::SysCtx; -impl From<&HostMemoryInfo> for GuestMemoryInfo { - fn from(value: &HostMemoryInfo) -> Self { +impl From<&HostMemoryStat> for GuestMemoryStat { + fn from(value: &HostMemoryStat) -> Self { Self { mem_total: value.mem_total, mem_free: value.mem_free, @@ -83,9 +84,9 @@ impl From<&HostMemoryInfo> for GuestMemoryInfo { } } -impl From<&HostMemoryModule> for GuestMemoryModule { - fn from(value: &HostMemoryModule) -> Self { - memory::MemoryModule { +impl From<&HostMemoryInfo> for GuestMemoryInfo { + fn from(value: &HostMemoryInfo) -> Self { + Self { array_handle: value.array_handle, error_info_handle: value.error_info_handle, total_width: value.total_width, @@ -127,23 +128,35 @@ impl From<&HostMemoryModule> for GuestMemoryModule { } impl memory::Host for SysCtx { - fn get_memory_info(&mut self) -> wasmtime::Result> { - let mem_info = parse_meminfo!().unwrap(); - Ok(Ok((&mem_info).into())) + fn stat(&mut self) -> wasmtime::Result> { + let mem_stat = match parse_meminfo!() { + Ok(ref info) => Ok(info.into()), + Err(err) => Err(err.to_string()), + }; + Ok(mem_stat) } - fn get_memory_module(&mut self) -> wasmtime::Result, String>> { - if let Some(dmidecode_exe) = which("dmidecode") { - let output = Command::new(dmidecode_exe).arg("-t").arg("17").output()?; + fn info(&mut self) -> wasmtime::Result, String>> { + // don't return top level Error because it will panic wasm + let get_mem_info = || -> Result, String> { + let Some(dmidecode_exe) = which("dmidecode") else { + return Err("Can not find `dmidecode` executable path.".to_string()); + }; + + let output = Command::new(dmidecode_exe) + .arg("-t") + .arg("17") + .output() + .map_err(|err| err.to_string())?; - let res = parse_memory_module(std::str::from_utf8(&output.stdout)?) + let content = std::str::from_utf8(&output.stdout).map_err(|err| err.to_string())?; + + Ok(parse_memory_module(content) .iter() - .map(GuestMemoryModule::from) - .collect::>(); + .map(GuestMemoryInfo::from) + .collect::>()) + }; - Ok(Ok(res)) - } else { - Ok(Err("Can not find `dmidecode` executable path.".to_string())) - } + Ok(get_mem_info()) } } diff --git a/crates/op/host-op-system/src/os/host.rs b/crates/op/host-op-system/src/os/host.rs index 84e9d83..d4afb44 100644 --- a/crates/op/host-op-system/src/os/host.rs +++ b/crates/op/host-op-system/src/os/host.rs @@ -12,15 +12,10 @@ // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . -use sysinfo::{ - DiskUsage as HostDiskUsage, Process as HostProcess, ProcessStatus as HostProcessStatus, -}; - use crate::{ profiling::system::os::{ - self, DiskUsage as GuestDiskUsage, DistroKind as GuestDistroKind, - DistroVersion as GuestDistroVersion, KernelVersion as GuestKernelVersion, - Process as GuestProcess, ProcessStatus as GuestProcessStatus, + self, DistroKind as GuestDistroKind, DistroVersion as GuestDistroVersion, + KernelVersion as GuestKernelVersion, OsInfo as GuestOsInfo, }, SysCtx, }; @@ -72,87 +67,17 @@ impl From<&HostKernelVersion> for GuestKernelVersion { } } -impl From<&HostDiskUsage> for GuestDiskUsage { - fn from(value: &HostDiskUsage) -> Self { - Self { - written_bytes: value.total_written_bytes, - read_bytes: value.total_read_bytes, - } - } -} - -impl From<&HostProcessStatus> for GuestProcessStatus { - fn from(value: &HostProcessStatus) -> Self { - match value { - HostProcessStatus::Idle => GuestProcessStatus::Idle, - HostProcessStatus::Run => GuestProcessStatus::Run, - HostProcessStatus::Sleep => GuestProcessStatus::Sleep, - HostProcessStatus::Stop => GuestProcessStatus::Stop, - HostProcessStatus::Zombie => GuestProcessStatus::Zombie, - HostProcessStatus::Tracing => GuestProcessStatus::Tracing, - HostProcessStatus::Dead => GuestProcessStatus::Dead, - HostProcessStatus::Wakekill => GuestProcessStatus::Wakekill, - HostProcessStatus::Waking => GuestProcessStatus::Waking, - HostProcessStatus::Parked => GuestProcessStatus::Parked, - HostProcessStatus::LockBlocked => GuestProcessStatus::LockBlocked, - HostProcessStatus::UninterruptibleDiskSleep => { - GuestProcessStatus::UninterruptibleDiskSleep - } - HostProcessStatus::Unknown(status) => GuestProcessStatus::Unknown(*status), - } - } -} - -impl From<&HostProcess> for GuestProcess { - fn from(value: &HostProcess) -> Self { - Self { - pid: value.pid().as_u32().into(), - name: value.name().to_owned(), - cmd: value.cmd().iter().map(|s| s.to_owned()).collect(), - exe: value.exe().and_then(|p| p.to_str().map(|s| s.to_owned())), - environ: value.environ().iter().map(|e| e.to_owned()).collect(), - cwd: value.cwd().and_then(|p| p.to_str().map(|s| s.to_owned())), - root: value.root().and_then(|p| p.to_str().map(|s| s.to_owned())), - start_time: value.start_time(), - parent_id: value.parent().map(|p| p.as_u32().into()), - user_id: value.user_id().map(|u| (*u.clone()).into()), - effective_user_id: value.effective_user_id().map(|u| (*u.clone()).into()), - group_id: value.group_id().map(|u| u64::from(*u)), - effective_group_id: value.effective_group_id().map(|u| u64::from(*u)), - run_time: value.run_time(), - status: (&value.status()).into(), - cpu_usage: value.cpu_usage(), - disk_usage: (&value.disk_usage()).into(), - memory_usage: value.memory(), - virtual_memory_usage: value.virtual_memory(), - } - } -} - impl os::Host for SysCtx { - fn get_distro_version(&mut self) -> wasmtime::Result> { - let res = match parse_distro_version!() { - Ok(distro) => Ok((&distro).into()), - Err(err) => Err(err.to_string()), + fn info(&mut self) -> wasmtime::Result> { + let distro = parse_distro_version!(); + let kernel = get_kernel_version(); + let info = match (distro, kernel) { + (Ok(ref distro_version), Ok(ref kernel_version)) => Ok(GuestOsInfo { + distro_version: distro_version.into(), + kernel_version: kernel_version.into(), + }), + _ => Err("Failed to retrieve os info".to_string()), }; - Ok(res) - } - - fn get_kernel_version(&mut self) -> wasmtime::Result> { - let res = match get_kernel_version() { - Ok(version) => Ok((&version).into()), - Err(err) => Err(err.to_string()), - }; - Ok(res) - } - - fn get_processes(&mut self) -> wasmtime::Result, String>> { - self.sys.refresh_processes(); - Ok(Ok(self - .sys - .processes() - .values() - .map(|p| p.into()) - .collect())) + Ok(info) } } diff --git a/crates/op/host-op-system/src/os/mod.rs b/crates/op/host-op-system/src/os/mod.rs index ae42b89..5c76696 100644 --- a/crates/op/host-op-system/src/os/mod.rs +++ b/crates/op/host-op-system/src/os/mod.rs @@ -11,6 +11,7 @@ // // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . + mod host; mod raw; diff --git a/crates/op/host-op-system/src/process/host.rs b/crates/op/host-op-system/src/process/host.rs new file mode 100644 index 0000000..5649ac3 --- /dev/null +++ b/crates/op/host-op-system/src/process/host.rs @@ -0,0 +1,172 @@ +// Copyright (c) 2023-2024 Optimatist Technology Co., Ltd. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This file is part of PSH. +// +// PSH is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// PSH is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, +// see . + +use std::{collections::HashMap, ffi::OsString, path::PathBuf}; + +use procfs::process::{ProcState, Process}; +use wasmtime::component::Resource; + +use crate::{ + profiling::system::process::{ + self, ProcessStat as GuestProcessStat, ProcessState as GuestProcessState, + }, + SysCtx, +}; + +impl From<&ProcState> for GuestProcessState { + fn from(value: &ProcState) -> Self { + match value { + ProcState::Running => Self::Running, + ProcState::Sleeping => Self::Sleeping, + ProcState::Waiting => Self::Waiting, + ProcState::Zombie => Self::Zombie, + ProcState::Stopped => Self::Stopped, + ProcState::Tracing => Self::Tracing, + ProcState::Dead => Self::Dead, + ProcState::Wakekill => Self::Wakekill, + ProcState::Waking => Self::Waking, + ProcState::Parked => Self::Parked, + ProcState::Idle => Self::Idle, + } + } +} + +fn path_to_str(path: PathBuf) -> String { + path.to_string_lossy().to_string() +} + +fn env_to_tuple((name, val): (OsString, OsString)) -> (String, String) { + let to_str = |os_str: OsString| os_str.to_string_lossy().to_string(); + (to_str(name), to_str(val)) +} + +fn envs_to_vec(vars: HashMap) -> Vec<(String, String)> { + vars.into_iter().map(env_to_tuple).collect::>() +} + +impl process::HostProcess for SysCtx { + fn pid(&mut self, self_: Resource) -> wasmtime::Result { + let process = self.table.get(&self_)?; + Ok(process.pid) + } + + fn cmd(&mut self, self_: Resource) -> wasmtime::Result, String>> { + let proc = self.table.get(&self_)?; + Ok(proc.cmdline().map_err(|err| err.to_string())) + } + + fn exe(&mut self, self_: Resource) -> wasmtime::Result> { + let proc = self.table.get(&self_)?; + Ok(proc.exe().map_err(|err| err.to_string()).map(path_to_str)) + } + + fn environ( + &mut self, + self_: Resource, + ) -> wasmtime::Result, String>> { + let proc = self.table.get(&self_)?; + Ok(proc + .environ() + .map_err(|err| err.to_string()) + .map(envs_to_vec)) + } + + fn cwd(&mut self, self_: Resource) -> wasmtime::Result> { + let proc = self.table.get(&self_)?; + Ok(proc.cwd().map_err(|err| err.to_string()).map(path_to_str)) + } + + fn root(&mut self, self_: Resource) -> wasmtime::Result> { + let proc = self.table.get(&self_)?; + Ok(proc.root().map_err(|err| err.to_string()).map(path_to_str)) + } + + fn user_id(&mut self, self_: Resource) -> wasmtime::Result> { + let proc = self.table.get(&self_)?; + Ok(proc.uid().map_err(|err| err.to_string())) + } + + fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { + self.table.delete(rep)?; + Ok(()) + } +} + +impl process::Host for SysCtx { + fn all(&mut self) -> wasmtime::Result, String>> { + // don't return top level Error unless it's not our fault + // example: self.table.(push/get/delete) + let proc_iter = match procfs::process::all_processes() { + Ok(proc_iter) => proc_iter, + Err(err) => { + return Ok(Err(err.to_string())); + } + }; + + let processes: Vec<_> = proc_iter + .filter_map(|proc| proc.ok()) + .filter_map(|proc| { + let (Ok(stat), Ok(io), Ok(mem)) = (proc.stat(), proc.io(), proc.statm()) else { + return None; + }; + let Ok(state) = stat.state() else { + return None; + }; + Some((proc, stat, io, mem, state)) + }) + .collect(); + + let processes: Vec<_> = processes + .into_iter() + .map(|(proc, stat, io, mem, ref state)| { + let (pid, parent_id) = (proc.pid, stat.ppid); + match self.table.push(proc) { + Ok(proc) => Ok(GuestProcessStat { + pid, + proc, + name: stat.comm, + utime: stat.utime * 1000 / self.tick_per_sec, + stime: stat.stime * 1000 / self.tick_per_sec, + cutime: stat.cutime * 1000 / self.tick_per_sec as i64, + cstime: stat.cstime * 1000 / self.tick_per_sec as i64, + priority: stat.priority, + nice: stat.nice, + num_threads: stat.num_threads, + start_time: stat.starttime * 1000 / self.tick_per_sec, + state: state.into(), + written_bytes: io.write_bytes, + read_bytes: io.read_bytes, + memory_usage: mem.resident * self.page_size, + virtual_memory_usage: mem.size * self.page_size, + parent_id, + }), + Err(err) => Err(err), + } + }) + .collect::>()?; // failure of this collect means self.table.push failed, so we give up + + Ok(Ok(processes)) + } + + fn current(&mut self) -> wasmtime::Result, String>> { + let proc = match procfs::process::Process::myself() { + Ok(proc) => { + let handle = self.table.push(proc)?; + Ok(handle) + } + Err(err) => Err(err.to_string()), + }; + Ok(proc) + } +} diff --git a/crates/op/host-op-system/src/process/mod.rs b/crates/op/host-op-system/src/process/mod.rs new file mode 100644 index 0000000..db121fc --- /dev/null +++ b/crates/op/host-op-system/src/process/mod.rs @@ -0,0 +1,15 @@ +// Copyright (c) 2023-2024 Optimatist Technology Co., Ltd. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This file is part of PSH. +// +// PSH is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// PSH is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, +// see . + +mod host; diff --git a/crates/op/host-op-system/src/rps/host.rs b/crates/op/host-op-system/src/rps/host.rs index 2912efd..fc39ae5 100644 --- a/crates/op/host-op-system/src/rps/host.rs +++ b/crates/op/host-op-system/src/rps/host.rs @@ -11,6 +11,7 @@ // // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . + use crate::profiling::system::rps::{self, RpsInfo as GuestRpsInfo, RpsQueue as GuestRpsQueue}; use crate::rps::{raw::parse_rps, RpsDetails as HostRpsInfo, RpsQueue as HostRpsQueue}; @@ -37,7 +38,7 @@ impl From<&HostRpsInfo> for GuestRpsInfo { } impl rps::Host for SysCtx { - fn get_rps_info(&mut self) -> wasmtime::Result> { + fn info(&mut self) -> wasmtime::Result> { Ok(parse_rps!().iter().map(|rps| rps.into()).collect()) } } diff --git a/examples/wasi/get_processes/src/main.rs b/examples/wasi/get_processes/src/main.rs index 8e30292..77e2848 100644 --- a/examples/wasi/get_processes/src/main.rs +++ b/examples/wasi/get_processes/src/main.rs @@ -11,20 +11,70 @@ // // You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not, // see . + #[rustfmt::skip] mod bindings; -use bindings::profiling::system::os; - -fn main() { - let name = std::env::args().nth(1).unwrap_or("psh".to_string()); - let mut processes = os::get_processes().unwrap_or(vec![]); - processes.sort_unstable_by(|lhs, rhs| rhs.cpu_usage.total_cmp(&lhs.cpu_usage)); - for process in processes - .iter() - .filter(|proc| proc.name.contains(&name)) - .take(10) - { - println!("{:?}", process); +use std::{collections::HashMap, error::Error}; + +#[derive(Debug, Clone, PartialEq, PartialOrd)] +pub struct ProcessUsage { + cpu: f64, + mem: u64, + wri: f64, + rea: f64, +} + +use bindings::profiling::system::process::{self, ProcessStat}; + +fn differential(pre: &ProcessStat, post: &ProcessStat, ms: u64) -> ProcessUsage { + ProcessUsage { + cpu: ((post.stime + post.utime) - (pre.stime + pre.utime)) as f64 / ms as f64, + mem: post.memory_usage, + wri: (post.written_bytes - pre.written_bytes) as f64 * 1000.0 / ms as f64, + rea: (post.read_bytes - pre.read_bytes) as f64 * 1000.0 / ms as f64, } } + +fn intersection<'p>( + pre: &'p Vec, + post: &'p Vec, +) -> HashMap { + let pre: HashMap = pre.iter().map(|p| (p.pid, p)).collect(); + let post: HashMap = post.iter().map(|p| (p.pid, p)).collect(); + pre.iter() + .filter_map(|(&pid, &pre_stat)| match post.get(&pid) { + Some(&post_stat) => Some((pid, (pre_stat, post_stat))), + None => None, + }) + .collect() +} + +fn main() -> Result<(), Box> { + let mut pre = process::all()?; + for _ in 0..100 { + std::thread::sleep(std::time::Duration::from_secs(1)); + let post = process::all()?; + + let common = intersection(&pre, &post); + let mut procs: Vec<_> = common + .values() + .map(|&(pre, post)| (pre, differential(pre, post, 1000))) + .collect(); + + procs.sort_unstable_by(|(_, lhs), (_, rhs)| rhs.cpu.total_cmp(&lhs.cpu)); + for (proc, usage) in procs.iter().take(5) { + println!( + "{:5} [{:36}] -> Cpu: {:6.2}% Wri: {:7.2}KiB/s", + proc.pid, + proc.name, + usage.cpu * 100.0 / 12.0, + usage.wri / 1024.0 + ); + } + println!(""); + pre = post; + } + + Ok(()) +} diff --git a/src/psh-sdk-wit b/src/psh-sdk-wit index 50dd470..6446b64 160000 --- a/src/psh-sdk-wit +++ b/src/psh-sdk-wit @@ -1 +1 @@ -Subproject commit 50dd4709070f71da845998219e7eb1b87c3937ca +Subproject commit 6446b64d118d37ddb7f03e9cc53cd8ff212be378