diff --git a/Cargo.lock b/Cargo.lock index 49dadb0..5222654 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -900,6 +900,13 @@ dependencies = [ "wit-bindgen 0.20.0", ] +[[package]] +name = "get_disks" +version = "0.1.0" +dependencies = [ + "wit-bindgen 0.20.0", +] + [[package]] name = "get_interrupts_info" version = "0.1.0" diff --git a/crates/op/host-op-system/src/disk/host.rs b/crates/op/host-op-system/src/disk/host.rs new file mode 100644 index 0000000..3b9b3d5 --- /dev/null +++ b/crates/op/host-op-system/src/disk/host.rs @@ -0,0 +1,73 @@ +// 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 crate::{ + profiling::system::disk::{ + self, DiskOperationStat as GuestDiskOperationStat, DiskStat as GuestDiskStat, + }, + SysCtx, +}; + +impl From<&procfs::DiskStat> for GuestDiskStat { + fn from(value: &procfs::DiskStat) -> Self { + let read = GuestDiskOperationStat { + operations: value.reads, + sectors: value.sectors_read, + merged: value.merged, + time: value.time_reading, + }; + let write = GuestDiskOperationStat { + operations: value.writes, + sectors: value.sectors_written, + merged: value.writes_merged, + time: value.time_writing, + }; + let discard = value + .discards + .zip(value.sectors_discarded) + .zip(value.discards_merged) + .zip(value.time_discarding) + .map( + |(((operations, sectors), merged), time)| GuestDiskOperationStat { + operations, + sectors, + merged, + time, + }, + ); + Self { + name: value.name.clone(), + major: value.major, + minor: value.minor, + read, + write, + discard, + in_progress: value.in_progress, + time_in_progress: value.time_in_progress, + weighted_time_in_progress: value.weighted_time_in_progress, + flushes: value.flushes, + time_flushing: value.time_flushing, + } + } +} + +impl disk::Host for SysCtx { + fn stat(&mut self) -> wasmtime::Result, String>> { + let disks = match procfs::diskstats() { + Ok(disks) => Ok(disks.iter().map(Into::into).collect()), + Err(err) => Err(err.to_string()), + }; + Ok(disks) + } +} diff --git a/crates/op/host-op-system/src/disk/mod.rs b/crates/op/host-op-system/src/disk/mod.rs new file mode 100644 index 0000000..db121fc --- /dev/null +++ b/crates/op/host-op-system/src/disk/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/lib.rs b/crates/op/host-op-system/src/lib.rs index 54dc982..f7e2e84 100644 --- a/crates/op/host-op-system/src/lib.rs +++ b/crates/op/host-op-system/src/lib.rs @@ -13,6 +13,7 @@ // see . mod cpu; +mod disk; mod interrupt; mod memory; mod network; diff --git a/examples/wasi/get_disks/Cargo.toml b/examples/wasi/get_disks/Cargo.toml new file mode 100644 index 0000000..1d18314 --- /dev/null +++ b/examples/wasi/get_disks/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "get_disks" +version = "0.1.0" +edition = "2021" + +[package.metadata.component] +package = "component:get-disks" + +[package.metadata.component.dependencies] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wit-bindgen = { version = "0.20.0", default-features = false, features = ["realloc"] } diff --git a/examples/wasi/get_disks/build.rs b/examples/wasi/get_disks/build.rs new file mode 100644 index 0000000..a202eaf --- /dev/null +++ b/examples/wasi/get_disks/build.rs @@ -0,0 +1,32 @@ +// 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::fs; +use std::ops::Not; +use std::process::Command; + +fn main() { + let _ = fs::remove_file("src/bindings.rs"); + let mut cmd = Command::new("wit-bindgen"); + cmd.args(["rust", "--stubs", "--out-dir", "src/", "../../../wit/"]); + + let output = cmd + .output() + .unwrap_or_else(|it| panic!("Failed to generate bindings: \n{}", it)); + if output.stderr.is_empty().not() { + panic!( + "Failed to generate bindings: \n{}", + String::from_utf8(output.stderr).unwrap() + ); + } +} diff --git a/examples/wasi/get_disks/src/main.rs b/examples/wasi/get_disks/src/main.rs new file mode 100644 index 0000000..3ca6d94 --- /dev/null +++ b/examples/wasi/get_disks/src/main.rs @@ -0,0 +1,90 @@ +// 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 . + +#[rustfmt::skip] +mod bindings; + +use std::{collections::HashMap, error::Error}; + +use bindings::profiling::system::disk::{self, DiskStat}; + +pub struct Usage { + bps: f64, + ops: f64, +} + +pub struct DiskUsage { + dev: String, + read: Usage, + write: Usage, +} + +fn usage(pre: &DiskStat, post: &DiskStat, dur: std::time::Duration) -> DiskUsage { + let ms = dur.as_millis() as f64; + let read_bps = (post.read.sectors - pre.read.sectors) as f64 * 512.0 * 1000.0 / ms; + let write_bps = (post.write.sectors - pre.write.sectors) as f64 * 512.0 * 1000.0 / ms; + let rps = (post.read.operations - pre.read.operations) as f64 * 1000.0 / ms; + let wps = (post.write.operations - pre.write.operations) as f64 * 1000.0 / ms; + DiskUsage { + dev: pre.name.clone(), + read: Usage { + bps: read_bps, + ops: rps, + }, + write: Usage { + bps: write_bps, + ops: wps, + }, + } +} + +fn differential(pre: &Vec, post: &Vec, dur: std::time::Duration) { + let pre: HashMap<_, _> = pre.iter().map(|d| (d.name.clone(), d)).collect(); + let post: HashMap<_, _> = post.iter().map(|d| (d.name.clone(), d)).collect(); + let mut usages: Vec<_> = pre + .iter() + .filter_map(|(name, &pre_stat)| match post.get(name) { + Some(&post_stat) => Some(usage(pre_stat, post_stat, dur)), + None => None, + }) + .collect(); + + usages.sort_unstable_by(|lhs, rhs| rhs.write.bps.total_cmp(&lhs.write.bps)); + + for du in usages { + println!( + "{:16}: Read {:8.2} KiB/s {:6.2} O/s, Write: {:8.2} KiB/s {:6.2} O/s", + du.dev, + du.read.bps / 1024.0, + du.read.ops, + du.write.bps / 1024.0, + du.write.ops + ); + } + println!(); +} + +fn main() -> Result<(), Box> { + let mut pre_now = std::time::Instant::now(); + let mut pre = disk::stat()?; + let dur = std::time::Duration::from_secs(1); + loop { + std::thread::sleep(dur); + let post_now = std::time::Instant::now(); + let post = disk::stat()?; + differential(&pre, &post, post_now - pre_now); + pre = post; + pre_now = post_now; + } +} diff --git a/src/psh-sdk-wit b/src/psh-sdk-wit index e1a7e23..b49da0c 160000 --- a/src/psh-sdk-wit +++ b/src/psh-sdk-wit @@ -1 +1 @@ -Subproject commit e1a7e236d4bc625f86fdc3726280e5818352e665 +Subproject commit b49da0c9d017c57b6238f3ab2a99dc5953c764c6