Skip to content
Merged
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
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "3"
members = ["crates/qdot", "crates/gguf", "crates/models", "crates/model", "crates/model-hf", "crates/placement", "crates/threads", "crates/levers", "crates/verbs", "crates/gpu", "crates/gpu-deepseek41", "crates/gpu-glm5next", "crates/gpu-mimo2", "crates/gpu-solar2", "crates/gpu-gemma-embedding2", "crates/gpu-gates", "crates/engram", "crates/engram-lab", "crates/sampler", "crates/tokenizer", "crates/serve", "crates/jinja", "crates/vision", "crates/gpu-vision", "crates/gpu-gemma4a", "crates/refset", "crates/runtime", "crates/app", "crates/decision", "crates/embed", "crates/hf", "crates/safetensors"]
members = ["crates/qdot", "crates/gguf", "crates/models", "crates/model", "crates/model-hf", "crates/placement", "crates/threads", "crates/levers", "crates/verbs", "crates/gpu", "crates/gpu-deepseek41", "crates/gpu-glm5next", "crates/gpu-mimo2", "crates/gpu-solar2", "crates/gpu-gemma-embedding2", "crates/gpu-gates", "crates/engram", "crates/engram-lab", "crates/sampler", "crates/tokenizer", "crates/serve", "crates/jinja", "crates/vision", "crates/gpu-vision", "crates/gpu-gemma4a", "crates/refset", "crates/runtime", "crates/app", "crates/decision", "crates/embed", "crates/hf", "crates/safetensors", "crates/os"]
# 의도적으로 컴파일되지 않는 재현기다(MUL-7). 워크스페이스에 넣으면 --workspace가 영구히 빨갛다.
exclude = ["crates/oxide-ice-unroll", "crates/oxide-ice-unroll/variants/unroll_smoke", "fuzz", "labs/hip-native"]

Expand All @@ -16,6 +16,9 @@ cuda-core = { version = "0.4.0", git = "https://github.com/NVIDIA/cuda-rust.git"
# one semver line unify into one version, so the gates cut the text handed to the driver with the loader's own code.
oxide-artifacts = "0.2.1"
libc = "0.2"
# The one owner of the operating-system calls the host chain makes: the crate
# that holds what Linux and macOS do differently.
bloomery-os = { path = "crates/os" }
# The decision head's host sgemm (crates/decision); its own threading stays off.
matrixmultiply = { version = "0.3.10", default-features = false, features = ["std"] }
memmap2 = "0.9"
Expand Down
1 change: 1 addition & 0 deletions crates/engram/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ workspace = true

[dependencies]
bloomery-gguf = { path = "../gguf" }
bloomery-os.workspace = true
bloomery-threads = { path = "../threads" }
libc.workspace = true
memmap2.workspace = true
Expand Down
13 changes: 4 additions & 9 deletions crates/engram/src/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,10 @@ pub const DIRECT_ALIGN: usize = 4096;
/// are multiples of [`DIRECT_ALIGN`]; the kernel refuses any other with
/// `EINVAL`.
pub fn open_direct(path: &Path) -> Result<File, EngramError> {
use std::os::unix::fs::OpenOptionsExt;
std::fs::OpenOptions::new()
.read(true)
.custom_flags(libc::O_DIRECT)
.open(path)
.map_err(|source| EngramError::OpenDirect {
path: path.to_path_buf(),
source,
})
os::open_direct(path).map_err(|source| EngramError::OpenDirect {
path: path.to_path_buf(),
source: source.into(),
})
}

/// A file read without the page cache ([`DirectFile::open`]) or through it
Expand Down
57 changes: 29 additions & 28 deletions crates/engram/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,21 +540,8 @@ impl Site {
/// `posix_fadvise(DONTNEED)` over `at .. at + len` of `file`: the page-cache
/// half of an eviction, after the mapping's own entries are dropped.
fn fadvise_dontneed(file: &File, at: usize, len: usize) -> Result<(), std::io::Error> {
// SAFETY: the descriptor is `file`'s own, borrowed for the call, and the
// range is plain numbers: fadvise reads and writes no memory of ours.
let rc = unsafe {
libc::posix_fadvise(
file.as_raw_fd(),
fadvise_off(at),
fadvise_off(len),
libc::POSIX_FADV_DONTNEED,
)
};
if rc == 0 {
Ok(())
} else {
Err(std::io::Error::from_raw_os_error(rc))
}
os::fadvise_dontneed(file.as_raw_fd(), fadvise_off(at), fadvise_off(len))
.map_err(std::io::Error::from)
}

/// `ids` as runs of adjacent rows, each `(first, last)` inclusive, sorted and
Expand Down Expand Up @@ -699,7 +686,16 @@ impl TableBytes<'_> {

/// [`Site::populate`]'s read: `POPULATE_READ` over each row's pages.
fn populate(&self, ids: &[u32]) -> Result<(), EngramError> {
self.advise(ids, libc::MADV_POPULATE_READ, "madvise(POPULATE_READ)")
let page = u64::try_from(self.page).expect("a page size fits a u64");
for &id in ids {
let (first, len) = self.pages(id)?;
let addr = first as *mut libc::c_void;
// SAFETY: the range is whole pages inside the mapping (`pages`
// rounds a row out to the mapping's own pages).
unsafe { os::populate_span(addr, len, page, || os::advise_populate(addr, len)) }
.map_err(|e| self.io("madvise(POPULATE_READ)", e.into()))?;
}
Ok(())
}

/// [`Site::resident_rows`]' count: the rows of `ids` whose pages `mincore`
Expand Down Expand Up @@ -748,14 +744,12 @@ impl TableBytes<'_> {
/// when the page is in the page cache.
fn mincore_chunk(&self, at: usize, len: usize) -> Result<[u8; MINCORE_PAGES], EngramError> {
let mut vec = [0u8; MINCORE_PAGES];
// SAFETY: `at .. at + len` is page-aligned and inside the mapping
// (`pages` rounds a row out to the mapping's own pages), and `vec`
// holds one byte for each of the at most `MINCORE_PAGES` pages of
// that range.
let rc = unsafe { libc::mincore(at as *mut libc::c_void, len, vec.as_mut_ptr()) };
if rc != 0 {
return Err(self.io("mincore", std::io::Error::last_os_error()));
}
// `at .. at +len` is page-aligned and inside the mapping (`pages`
// rounds a row out to the mapping's own pages), and `vec` holds one
// byte for each of the at most `MINCORE_PAGES` pages of that range.
// SAFETY: the caller's contract above.
unsafe { os::mincore(at as *mut libc::c_void, len, &mut vec) }
.map_err(|e| self.io("mincore", e.into()))?;
Ok(vec)
}

Expand Down Expand Up @@ -938,19 +932,26 @@ pub fn faults() -> Faults {
/// This is the counter a helper-thread design needs: the process total cannot
/// say which thread paid for a fault, and the whole claim of moving the read
/// off the step thread is that the step thread stops taking them. Sample it on
/// the thread it describes — a thread cannot ask for another's.
/// the thread it describes — a thread cannot ask for another's. Linux only: a
/// kernel without `RUSAGE_THREAD` (macOS) refuses it, and that panics by name.
pub fn faults_thread() -> Faults {
faults_of(RUSAGE_THREAD)
}

fn faults_of(who: libc::c_int) -> Faults {
// SAFETY: `usage` is a live, writable `rusage` for the duration of the call
// and `getrusage` fills it or leaves it untouched.
let usage = unsafe {
let (rc, usage) = unsafe {
let mut usage: libc::rusage = std::mem::zeroed();
libc::getrusage(who, &mut usage);
usage
let rc = libc::getrusage(who, &mut usage);
(rc, usage)
};
assert_eq!(
rc,
0,
"getrusage({who}) refused: {}",
std::io::Error::last_os_error()
);
Faults {
major: usage.ru_majflt.max(0) as u64,
minor: usage.ru_minflt.max(0) as u64,
Expand Down
14 changes: 11 additions & 3 deletions crates/engram/tests/engram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,8 +866,15 @@ fn hw_engram_expert_stack_evicts_and_reads_back() {
/// A direct handle reads the file's bytes at an aligned offset into an aligned
/// buffer, carries the `O_DIRECT` flag, and a path that is not there is
/// refused by name.
#[cfg_attr(
target_os = "linux",
ignore = "hw: the box's disk-backed target directory"
)]
#[cfg_attr(
not(target_os = "linux"),
ignore = "the Linux fact it reads: the open flags in /proc/self/fdinfo"
)]
#[test]
#[ignore = "hw: the box's disk-backed target directory"]
fn hw_engram_open_direct_reads_the_files_bytes() {
use std::os::fd::AsRawFd;
let scratch = Scratch::new("direct");
Expand All @@ -881,10 +888,11 @@ fn hw_engram_open_direct_reads_the_files_bytes() {
.find_map(|l| l.strip_prefix("flags:"))
.map(|v| u32::from_str_radix(v.trim(), 8).unwrap())
.expect("fdinfo names the open flags");
let direct_flag = os::DIRECT_FLAG.expect("this platform has a direct-open flag");
assert_ne!(
flags & libc::O_DIRECT as u32,
flags & direct_flag,
0,
"the handle carries O_DIRECT: flags {flags:o}"
"the handle carries the direct flag: flags {flags:o}"
);

let align = engram::DIRECT_ALIGN;
Expand Down
2 changes: 2 additions & 0 deletions crates/gguf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ sha2.workspace = true
thiserror.workspace = true

[dev-dependencies]
# The lib test reads a thread's own page faults.
bloomery-os.workspace = true
libc.workspace = true
# The dequant oracle's sets open through their refset family; refset reads the GGUF files
# through this crate, so the tests link the lib once and refset beside it.
Expand Down
11 changes: 5 additions & 6 deletions crates/gguf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1321,16 +1321,15 @@ mod split_tests {

/// Page faults the calling thread has taken, minor and major.
fn thread_faults() -> u64 {
// SAFETY: `rusage` is a C struct of integers; all-zero bytes are a value of it.
let mut usage: libc::rusage = unsafe { std::mem::zeroed() };
// SAFETY: `usage` is a live, writable `rusage` for the duration of the call.
let rc = unsafe { libc::getrusage(libc::RUSAGE_THREAD, &mut usage) };
assert_eq!(rc, 0, "getrusage(RUSAGE_THREAD)");
u64::try_from(usage.ru_minflt + usage.ru_majflt).unwrap()
os::thread_faults().expect("getrusage(RUSAGE_THREAD)")
}

/// A file refused by the strict pass costs a populating open its header's
/// pages, not its data's: the populate waits for the validation.
#[cfg_attr(
not(target_os = "linux"),
ignore = "the Linux fact it reads: a per-thread page-fault count"
)]
#[test]
fn a_refused_file_is_not_populated() {
const DATA: usize = 64 << 20;
Expand Down
3 changes: 3 additions & 0 deletions crates/model/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ workspace = true
bloomery-gguf = { path = "../gguf" }
bloomery-levers = { path = "../levers" }
bloomery-models = { path = "../models" }
# The OS calls the placement path makes (the affinity mask, the page-cache
# advice, the resident-page count) are the one owner's.
bloomery-os.workspace = true
# The placement planner, as a pure crate so its tests run on the Mac; this
# crate re-exports it at `placement` and keeps the parts the Mac cannot run
# (host_lock, workstation::host_available) beside the re-export.
Expand Down
36 changes: 2 additions & 34 deletions crates/model/src/fileio.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,15 @@
//! File-system calls std does not wrap. Each returns the bare `io::Error`;
//! the caller names the path and the operation.

use std::ffi::CString;
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;

/// `p` as a C string; a path holding a NUL is `InvalidInput`.
fn c_path(p: &Path) -> io::Result<CString> {
CString::new(p.as_os_str().as_bytes())
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
}

/// Bytes free to this process on the filesystem that holds `dir`.
pub fn free_bytes(dir: &Path) -> io::Result<u64> {
let c = c_path(dir)?;
let mut st = std::mem::MaybeUninit::<libc::statvfs>::uninit();
// SAFETY: `c` is a NUL-terminated path that lives across the call, and
// `st` is storage for one `statvfs`, which the call fills on success.
if unsafe { libc::statvfs(c.as_ptr(), st.as_mut_ptr()) } != 0 {
return Err(io::Error::last_os_error());
}
// SAFETY: the call returned 0, so it wrote every field of `st`.
let st = unsafe { st.assume_init() };
Ok(st.f_bavail.saturating_mul(st.f_frsize))
os::free_bytes(dir).map_err(io::Error::from)
}

/// Rename `from` to `to`, refused with `AlreadyExists` when `to` exists.
pub fn rename_noreplace(from: &Path, to: &Path) -> io::Result<()> {
let (a, b) = (c_path(from)?, c_path(to)?);
// SAFETY: both are NUL-terminated paths that live across the call.
let rc = unsafe {
libc::renameat2(
libc::AT_FDCWD,
a.as_ptr(),
libc::AT_FDCWD,
b.as_ptr(),
libc::RENAME_NOREPLACE,
)
};
if rc == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
os::rename_noreplace(from, to).map_err(io::Error::from)
}
Loading
Loading