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