Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add bindings for retrieving system metrics #4

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[unstable]
unstable-options = true
build-std = ["std", "core", "alloc"]

[build]
target = [
"aarch64-apple-darwin",
"x86_64-pc-windows-gnu",
"x86_64-unknown-freebsd",
"aarch64-unknown-linux-gnu",
]

[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=-crt-static"]
rustflags = ["-C", "target-feature=-crt-static"]
13 changes: 0 additions & 13 deletions .npmignore

This file was deleted.

1 change: 0 additions & 1 deletion .nvmrc

This file was deleted.

20 changes: 20 additions & 0 deletions .zed/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings
{
"lsp": {
"rust-analyzer": {
"initialization_settings": {
"check": {
"targets": [
"aarch64-apple-darwin",
"x86_64-pc-windows-gnu",
"aarch64-unknown-linux-gnu"
]
},
"cargo": { "target": null }
}
}
}
}
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ version = "0.0.10"
[lib]
crate-type = ["cdylib"]

[workspace]
members = [".", "crates/*"]

[dependencies]
aho-corasick = "1.0.1"
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.0", default-features = false, features = ["napi4"] }
napi-derive = "2.12.2"
zip = { version = "0.6.4" }
slacc-system-metrics = { version = "0.0.10", path = "./crates/slacc-system-metrics", features = [
"napi",
"nonblocking",
] }

[build-dependencies]
napi-build = "2.0.1"
Expand Down
6 changes: 6 additions & 0 deletions Cross.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[target.x86_64-unknown-freebsd]
image = "x/x86_64-unknown-freebsd-cross:latest"

[target.aarch64-unknown-freebsd]
build-std = true
image = "x/aarch64-unknown-freebsd-cross:latest"
107 changes: 107 additions & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
[tasks.build-darwin]
command = "cargo"
args = [
"build",
"--bins",
"--package=slacc-system-metrics",
"--target=aarch64-apple-darwin",
]

[tasks.build-windows]
command = "cargo"
args = [
"build",
"--bins",
"--package=slacc-system-metrics",
"--target=x86_64-pc-windows-gnu",
]

[tasks.build-linux]
command = "cargo"
args = [
"build",
"--bins",
"--package=slacc-system-metrics",
"--target=aarch64-unknown-linux-gnu",
]

[tasks.build-freebsd-amd]
command = "cross"
env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64" }
args = [
"build",
"--bins",
"--package=slacc-system-metrics",
"--target=x86_64-unknown-freebsd",
]

[tasks.build-freebsd-arm]
command = "cross"
env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64" }
args = [
"build",
"--bins",
"--package=slacc-system-metrics",
"--target=aarch64-unknown-freebsd",
]

[tasks.build-darwin-napi]
command = "napi"
args = ["build", "--platform", "--release", "--target=aarch64-apple-darwin"]

[tasks.build-windows-napi]
command = "napi"
args = ["build", "--platform", "--release", "--target=x86_64-pc-windows-gnu"]

[tasks.build-windows-msvc-napi]
env = { CARGO = "cargo-xwin" }
command = "napi"
args = ["build", "--platform", "--release", "--target=x86_64-pc-windows-msvc"]

[tasks.build-linux-napi]
command = "napi"
args = [
"build",
"--platform",
"--release",
"--target=aarch64-unknown-linux-gnu",
]

[tasks.build-freebsd-napi-amd]
command = "napi"
env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64", CARGO = "cross" }
args = ["build", "--platform", "--release", "--target=x86_64-unknown-freebsd"]

[tasks.build-freebsd-napi-arm]
command = "napi"
env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64", CARGO = "cross" }
args = ["build", "--platform", "--release", "--target=aarch64-unknown-freebsd"]

[tasks.build-napi]
clear = true
command = "cargo"
args = ["check"]
dependencies = [
"clean",
"build-linux-napi",
"build-darwin-napi",
"build-windows-msvc-napi",
"build-freebsd-napi-amd",
"build-freebsd-napi-arm",
]

[tasks.build]
clear = true
command = "cargo"
args = ["check"]
dependencies = [
"clean",
"build-linux",
"build-darwin",
"build-windows",
"build-freebsd-amd",
"build-freebsd-arm",
]

[config]
default_to_workspace = false
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extern crate napi_build;

fn main() {
napi_build::setup();
napi_build::setup();
}
34 changes: 34 additions & 0 deletions crates/slacc-system-metrics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "slacc-system-metrics"
version = "0.0.10"
edition = "2021"

[dependencies]
num = "0.4.1"
napi = { version = "2.12.2", default-features = false, optional = true }
napi-derive = { version = "2.12.2", optional = true }
clap = { version = "4.5.0", features = ["derive"] }
core-foundation-sys = "0.8.6"
errno = "0.3.8"
libc = "0.2"
thiserror = "1.0.56"
miette = { version = "7.1.0", features = ["fancy"] }

[features]
napi = ["napi/napi4", "napi-derive"]
nonblocking = ["napi"]

[target.'cfg(windows)'.dependencies]
windows = { version = "0.54.0", features = [
"Win32_Security",
"Win32_System_IO",
"Win32_Foundation",
"Win32_System_Ioctl",
"Win32_Storage_FileSystem",
"Win32_NetworkManagement_Ndis",
"Win32_NetworkManagement_IpHelper",
] }

[[bin]]
name = "slacc-system-metrics"
path = "src/main.rs"
5 changes: 5 additions & 0 deletions crates/slacc-system-metrics/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main() {
if std::env::var("TARGET").unwrap().contains("darwin") {
println!("cargo:rustc-link-lib=framework=IOKit");
}
}
157 changes: 157 additions & 0 deletions crates/slacc-system-metrics/src/freebsd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (c) 2024 Misskey and chocolate-pie */

use crate::{ErrnoExt, SlaccStatsError};
use libc::devstat_trans_flags;

// https://github.com/ziglang/zig/blob/13a9d94a8038727469cf11b72273ce4ea6d89faa/lib/std/Target.zig#L2489-L2502
// https://github.com/ziglang/zig/blob/13a9d94a8038727469cf11b72273ce4ea6d89faa/lib/std/Target.zig#L2226-L2276
// https://github.com/llvm/llvm-project/blob/7ac7d418ac2b16fd44789dcf48e2b5d73de3e715/clang/lib/Basic/Targets/X86.h#L444-L445
// https://github.com/llvm/llvm-project/blob/7ac7d418ac2b16fd44789dcf48e2b5d73de3e715/clang/lib/Basic/Targets/X86.h#L724-L725
// https://github.com/llvm/llvm-project/blob/7ac7d418ac2b16fd44789dcf48e2b5d73de3e715/clang/lib/Basic/Targets/AArch64.cpp#L161
#[repr(C, align(16))]
#[allow(non_camel_case_types)]
pub(crate) struct f128([u8; 16]);

#[repr(C)]
#[allow(non_camel_case_types)]
pub(crate) struct statinfo {
cp_time: [::libc::c_long; 5],
tk_nin: ::libc::c_long,
tk_nout: ::libc::c_long,
dinfo: *mut ::libc::devinfo,
snap_time: f128,
}

#[derive(Debug, Clone)]
pub(crate) struct DiskInformation {
pub(crate) read_count: u64,
pub(crate) write_count: u64,
}

#[derive(Debug, Clone)]
pub(crate) struct NetworkInformation {
pub(crate) read_bytes: u64,
pub(crate) write_bytes: u64,
}

#[derive(Debug, Clone)]
pub(crate) struct MemoryInformation {
pub(crate) used_count: u64,
pub(crate) total_count: u64,
pub(crate) active_count: u64,
}

macro_rules! sysctlbyname {
($system: literal, $output: ident, $ty: ty) => {{
let command = ::std::ffi::CString::new($system).unwrap();
libc::sysctlbyname(
command.as_ptr(),
&raw mut $output as *mut ::libc::c_void,
&mut std::mem::size_of::<$ty>(),
std::ptr::null_mut(),
0,
)
}};
}

#[link(name = "devstat")]
extern "C" {
pub(crate) static devstat_errbuf: [::libc::c_char; 2048];
pub(crate) fn devstat_getdevs(kd: *mut ::libc::kvm_t, stats: *mut statinfo) -> ::libc::c_int;
}

pub(crate) unsafe fn get_disk_io() -> Result<DiskInformation, SlaccStatsError> {
let mut read_total: u64 = 0;
let mut write_total: u64 = 0;
let mut devinfo = std::mem::zeroed::<::libc::devinfo>();
let mut statistic = std::mem::zeroed::<statinfo>();
statistic.dinfo = &mut devinfo;
devstat_getdevs(std::ptr::null_mut(), &mut statistic)
.into_error_with(|input| input >= 0)
.map_err(|_| SlaccStatsError::from_ptr(devstat_errbuf.as_ptr()))?;
let devices = std::slice::from_raw_parts(devinfo.devices, devinfo.numdevs as _);
for device in devices {
let read_count = device.operations[devstat_trans_flags::DEVSTAT_READ as usize];
let write_count = device.operations[devstat_trans_flags::DEVSTAT_WRITE as usize];
read_total = read_total.saturating_add(read_count);
write_total = write_total.saturating_add(write_count);
}
libc::free(devinfo.mem_ptr as *mut _);
Ok(DiskInformation {
read_count: read_total,
write_count: write_total,
})
}

pub(crate) unsafe fn get_network_info() -> Result<NetworkInformation, SlaccStatsError> {
let mut interface_count: ::libc::c_int = 0;
let mut read_total: u64 = 0;
let mut write_total: u64 = 0;
let command = [
libc::CTL_NET,
libc::PF_LINK,
libc::NETLINK_GENERIC,
libc::IFMIB_SYSTEM,
libc::IFMIB_IFCOUNT,
];

libc::sysctl(
command.as_ptr(),
command.len() as ::libc::c_uint,
&raw mut interface_count as *mut ::libc::c_void,
&mut std::mem::size_of::<::libc::c_int>(),
std::ptr::null_mut(),
0,
)
.into_errno()?;

for index in 1..=interface_count {
let mut data = std::mem::zeroed::<::libc::ifmibdata>();
let command = [
libc::CTL_NET,
libc::PF_LINK,
libc::NETLINK_GENERIC,
libc::IFMIB_IFDATA,
index,
libc::IFDATA_GENERAL,
];
libc::sysctl(
command.as_ptr(),
command.len() as ::libc::c_uint,
&raw mut data as *mut ::libc::c_void,
&mut std::mem::size_of::<::libc::ifmibdata>(),
std::ptr::null_mut(),
0,
)
.into_errno()?;
let read_count = data.ifmd_data.ifi_ibytes;
let write_count = data.ifmd_data.ifi_obytes;
read_total = read_total.saturating_add(read_count);
write_total = write_total.saturating_add(write_count);
}

Ok(NetworkInformation {
read_bytes: read_total,
write_bytes: write_total,
})
}

pub(crate) unsafe fn get_memory_info() -> Result<MemoryInformation, SlaccStatsError> {
let mut page_size: u64 = 0;
let mut free_memory: u64 = 0;
let mut total_memory: u64 = 0;
let mut active_memory: u64 = 0;
sysctlbyname!("hw.realmem", total_memory, u64).into_errno()?;
sysctlbyname!("vm.stats.vm.v_page_size", page_size, u64).into_errno()?;
sysctlbyname!("vm.stats.vm.v_free_count", free_memory, u64).into_errno()?;
sysctlbyname!("vm.stats.vm.v_active_count", active_memory, u64).into_errno()?;
let free_memory = free_memory.saturating_mul(page_size);
let active_memory = active_memory.saturating_mul(page_size);
let used_memory = total_memory.saturating_sub(free_memory);
Ok(MemoryInformation {
used_count: used_memory,
active_count: active_memory,
total_count: total_memory,
})
}
Loading