mirror of
https://github.com/NotAShelf/microfetch.git
synced 2026-04-12 12:57:41 +00:00
chore: don't benchmark binary crate; centralize assembly helpers
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ia24cb1647df93034937a8fcd6cad895c6a6a6964
This commit is contained in:
parent
1408ca9f38
commit
1c781aff56
7 changed files with 203 additions and 103 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -417,9 +417,9 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hotpath"
|
name = "hotpath"
|
||||||
version = "0.13.0"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51462b35dc551217e1d1dd3f8c5eebbb5df7103370b1e55d24c19a3411d290f7"
|
checksum = "2fde50be006a0fe95cc2fd6d25d884aa6932218e4055d7df2fa0d95c386acf8d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
@ -444,9 +444,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hotpath-macros"
|
name = "hotpath-macros"
|
||||||
version = "0.13.0"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f022365c90cc04455f17a2b9ba5fe0e661cde1ab27434d382f1f8693fe124e7d"
|
checksum = "dd884cee056e269e41e1127549458e1c4e309f31897ebbc1416982a74d40a5b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -550,6 +550,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
name = "microfetch"
|
name = "microfetch"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"hotpath",
|
||||||
"microfetch-lib",
|
"microfetch-lib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,20 @@
|
||||||
//! What do you mean I wasted two whole hours to make the program only 100µs
|
//! What do you mean I wasted two whole hours to make the program only 100µs
|
||||||
//! faster?
|
//! faster?
|
||||||
//!
|
//!
|
||||||
//! Supports `x86_64` and `aarch64` architectures. Riscv support will be
|
//! Supports `x86_64`, `aarch64`, and `riscv64` architectures.
|
||||||
//! implemented when and ONLY WHEN I can be bothered to work on it.
|
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
// Ensure we're compiling for a supported architecture.
|
||||||
|
#[cfg(not(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "riscv64"
|
||||||
|
)))]
|
||||||
|
compile_error!(
|
||||||
|
"Unsupported architecture: only x86_64, aarch64, and riscv64 are supported"
|
||||||
|
);
|
||||||
|
|
||||||
/// Direct syscall to open a file
|
/// Direct syscall to open a file
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
|
|
@ -62,9 +71,24 @@ pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 {
|
||||||
fd as i32
|
fd as i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let fd: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") 56i64, // SYS_openat
|
||||||
|
in("a0") -100i32, // AT_FDCWD
|
||||||
|
in("a1") path,
|
||||||
|
in("a2") flags,
|
||||||
|
in("a3") 0i32, // mode
|
||||||
|
lateout("a0") fd,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
{
|
{
|
||||||
compile_error!("Unsupported architecture for inline assembly syscalls");
|
fd as i32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,9 +146,23 @@ pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") 63i64, // SYS_read
|
||||||
|
in("a0") fd,
|
||||||
|
in("a1") buf,
|
||||||
|
in("a2") count,
|
||||||
|
lateout("a0") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
{
|
{
|
||||||
compile_error!("Unsupported architecture for inline assembly syscalls");
|
ret as isize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,9 +221,23 @@ pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") 64i64, // SYS_write
|
||||||
|
in("a0") fd,
|
||||||
|
in("a1") buf,
|
||||||
|
in("a2") count,
|
||||||
|
lateout("a0") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
{
|
{
|
||||||
compile_error!("Unsupported architecture for inline assembly syscalls");
|
ret as isize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,9 +283,20 @@ pub unsafe fn sys_close(fd: i32) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") 57i64, // SYS_close
|
||||||
|
in("a0") fd,
|
||||||
|
lateout("a0") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
{
|
{
|
||||||
compile_error!("Unsupported architecture for inline assembly syscalls");
|
ret as i32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,9 +363,21 @@ pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") 160i64, // SYS_uname
|
||||||
|
in("a0") buf,
|
||||||
|
lateout("a0") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
{
|
{
|
||||||
compile_error!("Unsupported architecture for inline assembly syscalls");
|
ret as i32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -381,9 +456,22 @@ pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") 43i64, // SYS_statfs
|
||||||
|
in("a0") path,
|
||||||
|
in("a1") buf,
|
||||||
|
lateout("a0") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
{
|
{
|
||||||
compile_error!("Unsupported architecture for inline assembly syscalls");
|
ret as i32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,3 +515,85 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> io::Result<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Raw buffer for the `sysinfo(2)` syscall.
|
||||||
|
///
|
||||||
|
/// In the Linux ABI `uptime` is a `long` at offset 0. The remaining fields are
|
||||||
|
/// not needed, but are declared to give the struct its correct size (112 bytes
|
||||||
|
/// on 64-bit Linux).
|
||||||
|
///
|
||||||
|
/// The layout matches the kernel's `struct sysinfo` *exactly*:
|
||||||
|
/// `mem_unit` ends at offset 108, then 4 bytes of implicit padding to 112.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SysInfo {
|
||||||
|
pub uptime: i64,
|
||||||
|
pub loads: [u64; 3],
|
||||||
|
pub totalram: u64,
|
||||||
|
pub freeram: u64,
|
||||||
|
pub sharedram: u64,
|
||||||
|
pub bufferram: u64,
|
||||||
|
pub totalswap: u64,
|
||||||
|
pub freeswap: u64,
|
||||||
|
pub procs: u16,
|
||||||
|
_pad: u16,
|
||||||
|
_pad2: u32, /* alignment padding to reach 8-byte boundary for
|
||||||
|
* totalhigh */
|
||||||
|
pub totalhigh: u64,
|
||||||
|
pub freehigh: u64,
|
||||||
|
pub mem_unit: u32,
|
||||||
|
// 4 bytes implicit trailing padding to reach 112 bytes total; no field
|
||||||
|
// needed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Direct `sysinfo(2)` syscall
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// 0 on success, negative errno on error
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller must ensure that `info` points to a valid `SysInfo` buffer.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rax") 99_i64, // __NR_sysinfo
|
||||||
|
in("rdi") info,
|
||||||
|
out("rcx") _,
|
||||||
|
out("r11") _,
|
||||||
|
lateout("rax") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"svc #0",
|
||||||
|
in("x8") 179_i64, // __NR_sysinfo
|
||||||
|
in("x0") info,
|
||||||
|
lateout("x0") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
unsafe {
|
||||||
|
let ret: i64;
|
||||||
|
std::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") 179_i64, // __NR_sysinfo
|
||||||
|
in("a0") info,
|
||||||
|
lateout("a0") ret,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,12 @@ license.workspace = true
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hotpath = { optional = true, version = "0.13.0" }
|
hotpath = { optional = true, version = "0.14.0" }
|
||||||
microfetch-asm.workspace = true
|
microfetch-asm.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
hotpath = [ "dep:hotpath", "hotpath/hotpath" ]
|
hotpath = [ "dep:hotpath", "hotpath/hotpath" ]
|
||||||
hotpath-alloc = [ "hotpath/hotpath-alloc" ]
|
hotpath-alloc = [ "hotpath/hotpath-alloc" ]
|
||||||
hotpath-off = [ "hotpath/hotpath-off" ]
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion.workspace = true
|
criterion.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,14 @@ use std::{
|
||||||
pub use microfetch_asm as syscall;
|
pub use microfetch_asm as syscall;
|
||||||
pub use microfetch_asm::{
|
pub use microfetch_asm::{
|
||||||
StatfsBuf,
|
StatfsBuf,
|
||||||
|
SysInfo,
|
||||||
UtsNameBuf,
|
UtsNameBuf,
|
||||||
read_file_fast,
|
read_file_fast,
|
||||||
sys_close,
|
sys_close,
|
||||||
sys_open,
|
sys_open,
|
||||||
sys_read,
|
sys_read,
|
||||||
sys_statfs,
|
sys_statfs,
|
||||||
|
sys_sysinfo,
|
||||||
sys_uname,
|
sys_uname,
|
||||||
sys_write,
|
sys_write,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use std::{io, mem::MaybeUninit};
|
use std::{io, mem::MaybeUninit};
|
||||||
|
|
||||||
|
use crate::syscall::sys_sysinfo;
|
||||||
|
|
||||||
/// Faster integer to string conversion without the formatting overhead.
|
/// Faster integer to string conversion without the formatting overhead.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn itoa(mut n: u64, buf: &mut [u8]) -> &str {
|
fn itoa(mut n: u64, buf: &mut [u8]) -> &str {
|
||||||
|
|
@ -17,79 +19,6 @@ fn itoa(mut n: u64, buf: &mut [u8]) -> &str {
|
||||||
unsafe { std::str::from_utf8_unchecked(&buf[i..]) }
|
unsafe { std::str::from_utf8_unchecked(&buf[i..]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw buffer for the `sysinfo(2)` syscall.
|
|
||||||
///
|
|
||||||
/// In the Linux ABI `uptime` is a `long` at offset 0. The remaining fields are
|
|
||||||
/// not needed, but are declared to give the struct its correct size (112 bytes
|
|
||||||
/// on 64-bit Linux).
|
|
||||||
///
|
|
||||||
/// The layout matches the kernel's `struct sysinfo` *exactly*:
|
|
||||||
/// `mem_unit` ends at offset 108, then 4 bytes of implicit padding to 112.
|
|
||||||
#[repr(C)]
|
|
||||||
struct SysInfo {
|
|
||||||
uptime: i64,
|
|
||||||
loads: [u64; 3],
|
|
||||||
totalram: u64,
|
|
||||||
freeram: u64,
|
|
||||||
sharedram: u64,
|
|
||||||
bufferram: u64,
|
|
||||||
totalswap: u64,
|
|
||||||
freeswap: u64,
|
|
||||||
procs: u16,
|
|
||||||
_pad: u16,
|
|
||||||
_pad2: u32, // alignment padding to reach 8-byte boundary for totalhigh
|
|
||||||
totalhigh: u64,
|
|
||||||
freehigh: u64,
|
|
||||||
mem_unit: u32,
|
|
||||||
// 4 bytes implicit trailing padding to reach 112 bytes total; no field
|
|
||||||
// needed
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Direct `sysinfo(2)` syscall using inline assembly
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The caller must ensure the sysinfo pointer is valid.
|
|
||||||
#[inline]
|
|
||||||
unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 {
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
{
|
|
||||||
let ret: i64;
|
|
||||||
unsafe {
|
|
||||||
std::arch::asm!(
|
|
||||||
"syscall",
|
|
||||||
in("rax") 99_i64, // __NR_sysinfo
|
|
||||||
in("rdi") info,
|
|
||||||
out("rcx") _,
|
|
||||||
out("r11") _,
|
|
||||||
lateout("rax") ret,
|
|
||||||
options(nostack)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
{
|
|
||||||
let ret: i64;
|
|
||||||
unsafe {
|
|
||||||
std::arch::asm!(
|
|
||||||
"svc #0",
|
|
||||||
in("x8") 179_i64, // __NR_sysinfo
|
|
||||||
in("x0") info,
|
|
||||||
lateout("x0") ret,
|
|
||||||
options(nostack)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
|
||||||
{
|
|
||||||
compile_error!("Unsupported architecture for inline assembly syscalls");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the current system uptime.
|
/// Gets the current system uptime.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@ repository = "https://github.com/notashelf/microfetch"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
hotpath = { optional = true, version = "0.14.0" }
|
||||||
microfetch-lib.workspace = true
|
microfetch-lib.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
hotpath = [ "microfetch-lib/hotpath" ]
|
hotpath = [ "dep:hotpath" ]
|
||||||
hotpath-alloc = [ "microfetch-lib/hotpath-alloc" ]
|
hotpath-alloc = [ "hotpath/hotpath-alloc" ]
|
||||||
hotpath-off = [ "microfetch-lib/hotpath-off" ]
|
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#[cfg_attr(feature = "hotpath", hotpath::main)]
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
microfetch_lib::run()
|
microfetch_lib::run()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue