#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MmapRegion {
pub data: Vec<u8>,
pub offset: u64,
pub length: u64,
}
impl MmapRegion {
#[must_use]
pub fn new(data: Vec<u8>, offset: u64) -> Self {
let length = data.len() as u64;
Self {
data,
offset,
length,
}
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn slice(&self, start: u64, len: usize) -> Option<&[u8]> {
let end = start.checked_add(len as u64)?;
if end > self.length {
return None;
}
let s = start as usize;
let e = end as usize;
Some(&self.data[s..e])
}
#[must_use]
pub fn read_u32_le(&self, offset: u64) -> Option<u32> {
let bytes = self.slice(offset, 4)?;
Some(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
}
#[must_use]
pub fn read_u64_le(&self, offset: u64) -> Option<u64> {
let bytes = self.slice(offset, 8)?;
Some(u64::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]))
}
}
#[derive(Debug, Default)]
pub struct MmapFile {
pub path: String,
pub regions: Vec<MmapRegion>,
pub total_size: u64,
}
impl MmapFile {
pub fn new(path: impl Into<String>) -> Self {
Self {
path: path.into(),
regions: Vec::new(),
total_size: 0,
}
}
pub fn map_region(&mut self, data: Vec<u8>, offset: u64) -> usize {
let region = MmapRegion::new(data, offset);
self.total_size += region.length;
self.regions.push(region);
self.regions.len() - 1
}
#[must_use]
pub fn get_region(&self, idx: usize) -> Option<&MmapRegion> {
self.regions.get(idx)
}
#[must_use]
pub fn total_mapped_bytes(&self) -> u64 {
self.total_size
}
}
#[derive(Debug)]
pub struct PageAlignedBuffer {
pub data: Vec<u8>,
pub page_size: usize,
}
impl PageAlignedBuffer {
#[must_use]
pub fn new(size: usize) -> Self {
const DEFAULT_PAGE_SIZE: usize = 4096;
Self::with_page_size(size, DEFAULT_PAGE_SIZE)
}
#[must_use]
pub fn with_page_size(size: usize, page_size: usize) -> Self {
assert!(page_size > 0, "page_size must be non-zero");
let pages = size.div_ceil(page_size).max(1);
let aligned = pages * page_size;
Self {
data: vec![0u8; aligned],
page_size,
}
}
#[must_use]
pub fn aligned_len(&self) -> usize {
self.data.len()
}
#[must_use]
pub fn page_count(&self) -> usize {
self.data.len() / self.page_size
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_region_new_sets_length() {
let r = MmapRegion::new(vec![1, 2, 3, 4], 0);
assert_eq!(r.length, 4);
assert_eq!(r.offset, 0);
}
#[test]
fn test_region_slice_full() {
let r = MmapRegion::new(vec![10, 20, 30], 0);
assert_eq!(r.slice(0, 3), Some([10u8, 20, 30].as_slice()));
}
#[test]
fn test_region_slice_partial() {
let r = MmapRegion::new(vec![1, 2, 3, 4, 5], 0);
assert_eq!(r.slice(1, 3), Some([2u8, 3, 4].as_slice()));
}
#[test]
fn test_region_slice_out_of_bounds() {
let r = MmapRegion::new(vec![0u8; 4], 0);
assert!(r.slice(3, 2).is_none());
}
#[test]
fn test_region_slice_empty() {
let r = MmapRegion::new(vec![9u8; 8], 100);
assert_eq!(r.slice(0, 0), Some([].as_slice()));
}
#[test]
fn test_region_read_u32_le() {
let r = MmapRegion::new(vec![0x04, 0x03, 0x02, 0x01], 0);
assert_eq!(r.read_u32_le(0), Some(0x0102_0304));
}
#[test]
fn test_region_read_u32_le_not_enough_bytes() {
let r = MmapRegion::new(vec![0, 1, 2], 0);
assert!(r.read_u32_le(0).is_none());
}
#[test]
fn test_region_read_u64_le() {
let bytes: Vec<u8> = (0u8..8).collect();
let r = MmapRegion::new(bytes, 0);
let expected = u64::from_le_bytes([0, 1, 2, 3, 4, 5, 6, 7]);
assert_eq!(r.read_u64_le(0), Some(expected));
}
#[test]
fn test_region_read_u64_le_not_enough_bytes() {
let r = MmapRegion::new(vec![0u8; 7], 0);
assert!(r.read_u64_le(0).is_none());
}
#[test]
fn test_mmap_file_map_region_returns_index() {
let mut f = MmapFile::new("test.bin");
let idx = f.map_region(vec![1, 2, 3], 0);
assert_eq!(idx, 0);
let idx2 = f.map_region(vec![4, 5], 3);
assert_eq!(idx2, 1);
}
#[test]
fn test_mmap_file_total_mapped_bytes() {
let mut f = MmapFile::new("x");
f.map_region(vec![0u8; 100], 0);
f.map_region(vec![0u8; 200], 100);
assert_eq!(f.total_mapped_bytes(), 300);
}
#[test]
fn test_mmap_file_get_region_valid() {
let mut f = MmapFile::new("x");
f.map_region(vec![42u8; 4], 0);
let r = f.get_region(0).expect("region 0 must exist");
assert_eq!(r.data, vec![42u8; 4]);
}
#[test]
fn test_mmap_file_get_region_out_of_bounds() {
let f = MmapFile::new("x");
assert!(f.get_region(0).is_none());
}
#[test]
fn test_page_aligned_buffer_exact_page() {
let buf = PageAlignedBuffer::new(4096);
assert_eq!(buf.aligned_len(), 4096);
assert_eq!(buf.page_count(), 1);
}
#[test]
fn test_page_aligned_buffer_rounds_up() {
let buf = PageAlignedBuffer::new(1);
assert_eq!(buf.aligned_len(), 4096);
assert_eq!(buf.page_count(), 1);
}
#[test]
fn test_page_aligned_buffer_multiple_pages() {
let buf = PageAlignedBuffer::new(8193);
assert_eq!(buf.aligned_len(), 4096 * 3);
assert_eq!(buf.page_count(), 3);
}
#[test]
fn test_page_aligned_buffer_custom_page_size() {
let buf = PageAlignedBuffer::with_page_size(100, 64);
assert_eq!(buf.aligned_len(), 128);
assert_eq!(buf.page_count(), 2);
}
#[test]
fn test_page_aligned_buffer_zero_size() {
let buf = PageAlignedBuffer::new(0);
assert_eq!(buf.aligned_len(), 4096);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum HugePageSize {
TwoMib,
OneGib,
Custom(usize),
}
impl HugePageSize {
#[must_use]
pub fn bytes(self) -> usize {
match self {
Self::TwoMib => 2 * 1024 * 1024,
Self::OneGib => 1024 * 1024 * 1024,
Self::Custom(n) => n,
}
}
}
impl std::fmt::Display for HugePageSize {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::TwoMib => write!(f, "2MiB"),
Self::OneGib => write!(f, "1GiB"),
Self::Custom(n) => write!(f, "custom-{}B", n),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum HugePagePolicy {
#[default]
Disabled,
Transparent,
Explicit(HugePageSize),
}
impl HugePagePolicy {
#[must_use]
pub fn is_enabled(&self) -> bool {
!matches!(self, Self::Disabled)
}
#[must_use]
pub fn explicit_size(&self) -> Option<HugePageSize> {
match self {
Self::Explicit(sz) => Some(*sz),
_ => None,
}
}
#[must_use]
pub fn description(&self) -> String {
match self {
Self::Disabled => "disabled".to_string(),
Self::Transparent => "transparent (MADV_HUGEPAGE)".to_string(),
Self::Explicit(sz) => format!("explicit MAP_HUGETLB ({})", sz),
}
}
}
pub const HUGE_PAGE_THRESHOLD_BYTES: u64 = 2 * 1024 * 1024;
#[derive(Debug, Clone)]
pub struct MmapRegionHuge {
pub region: MmapRegion,
pub policy: HugePagePolicy,
pub huge_pages_active: bool,
}
impl MmapRegionHuge {
#[must_use]
pub fn new(data: Vec<u8>, offset: u64, policy: HugePagePolicy) -> Self {
let large_enough = data.len() as u64 >= HUGE_PAGE_THRESHOLD_BYTES;
let huge_pages_active = policy.is_enabled() && large_enough;
let region = MmapRegion::new(data, offset);
Self {
region,
policy,
huge_pages_active,
}
}
#[must_use]
pub fn required_huge_pages(&self) -> Option<usize> {
let sz = match self.policy {
HugePagePolicy::Explicit(sz) => sz,
_ => return None,
};
let page_bytes = sz.bytes();
if page_bytes == 0 {
return None;
}
Some(self.region.length.div_ceil(page_bytes as u64) as usize)
}
#[must_use]
pub fn slice(&self, start: u64, len: usize) -> Option<&[u8]> {
self.region.slice(start, len)
}
}
#[derive(Debug, Default)]
pub struct MmapFileHuge {
pub path: String,
pub regions: Vec<MmapRegionHuge>,
pub total_size: u64,
pub default_policy: HugePagePolicy,
}
impl MmapFileHuge {
#[must_use]
pub fn new(path: impl Into<String>, default_policy: HugePagePolicy) -> Self {
Self {
path: path.into(),
regions: Vec::new(),
total_size: 0,
default_policy,
}
}
pub fn map_region(&mut self, data: Vec<u8>, offset: u64) -> usize {
let policy = if data.len() as u64 >= HUGE_PAGE_THRESHOLD_BYTES {
self.default_policy
} else {
HugePagePolicy::Disabled
};
self.map_region_with_policy(data, offset, policy)
}
pub fn map_region_with_policy(
&mut self,
data: Vec<u8>,
offset: u64,
policy: HugePagePolicy,
) -> usize {
let region = MmapRegionHuge::new(data, offset, policy);
self.total_size += region.region.length;
self.regions.push(region);
self.regions.len() - 1
}
#[must_use]
pub fn huge_page_region_count(&self) -> usize {
self.regions.iter().filter(|r| r.huge_pages_active).count()
}
#[must_use]
pub fn huge_page_bytes(&self) -> u64 {
self.regions
.iter()
.filter(|r| r.huge_pages_active)
.map(|r| r.region.length)
.sum()
}
}
#[cfg(test)]
mod huge_page_tests {
use super::*;
#[test]
fn test_huge_page_size_bytes() {
assert_eq!(HugePageSize::TwoMib.bytes(), 2 * 1024 * 1024);
assert_eq!(HugePageSize::OneGib.bytes(), 1024 * 1024 * 1024);
assert_eq!(HugePageSize::Custom(4096).bytes(), 4096);
}
#[test]
fn test_huge_page_size_display() {
assert_eq!(HugePageSize::TwoMib.to_string(), "2MiB");
assert_eq!(HugePageSize::OneGib.to_string(), "1GiB");
assert_eq!(HugePageSize::Custom(8192).to_string(), "custom-8192B");
}
#[test]
fn test_huge_page_policy_disabled() {
let p = HugePagePolicy::Disabled;
assert!(!p.is_enabled());
assert!(p.explicit_size().is_none());
}
#[test]
fn test_huge_page_policy_transparent() {
let p = HugePagePolicy::Transparent;
assert!(p.is_enabled());
assert!(p.explicit_size().is_none());
assert!(p.description().contains("MADV_HUGEPAGE"));
}
#[test]
fn test_huge_page_policy_explicit() {
let p = HugePagePolicy::Explicit(HugePageSize::TwoMib);
assert!(p.is_enabled());
assert_eq!(p.explicit_size(), Some(HugePageSize::TwoMib));
assert!(p.description().contains("MAP_HUGETLB"));
}
#[test]
fn test_mmap_region_huge_small_data_disabled() {
let data = vec![0u8; 1024]; let region = MmapRegionHuge::new(data, 0, HugePagePolicy::Transparent);
assert!(!region.huge_pages_active);
}
#[test]
fn test_mmap_region_huge_large_data_transparent() {
let data = vec![0u8; 2 * 1024 * 1024];
let region = MmapRegionHuge::new(data, 0, HugePagePolicy::Transparent);
assert!(region.huge_pages_active);
}
#[test]
fn test_mmap_region_huge_required_pages() {
let data = vec![0u8; 4 * 1024 * 1024]; let region = MmapRegionHuge::new(data, 0, HugePagePolicy::Explicit(HugePageSize::TwoMib));
assert_eq!(region.required_huge_pages(), Some(2));
}
#[test]
fn test_mmap_region_huge_required_pages_none_when_transparent() {
let data = vec![0u8; 4 * 1024 * 1024];
let region = MmapRegionHuge::new(data, 0, HugePagePolicy::Transparent);
assert_eq!(region.required_huge_pages(), None);
}
#[test]
fn test_mmap_region_huge_slice() {
let data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
let region = MmapRegionHuge::new(data, 0, HugePagePolicy::Disabled);
assert_eq!(region.slice(2, 3), Some([3u8, 4, 5].as_slice()));
}
#[test]
fn test_mmap_file_huge_map_regions() {
let mut f = MmapFileHuge::new("big.raw", HugePagePolicy::Transparent);
let idx0 = f.map_region(vec![0u8; 512], 0);
let large = vec![0u8; 2 * 1024 * 1024];
let idx1 = f.map_region(large, 512);
assert_eq!(idx0, 0);
assert_eq!(idx1, 1);
assert_eq!(f.huge_page_region_count(), 1);
}
#[test]
fn test_mmap_file_huge_bytes() {
let mut f = MmapFileHuge::new("x", HugePagePolicy::Explicit(HugePageSize::TwoMib));
let large = vec![0u8; 2 * 1024 * 1024];
f.map_region(large, 0);
assert_eq!(f.huge_page_bytes(), 2 * 1024 * 1024);
}
#[test]
fn test_mmap_file_huge_policy_override() {
let mut f = MmapFileHuge::new("x", HugePagePolicy::Disabled);
f.map_region_with_policy(
vec![0u8; 16],
0,
HugePagePolicy::Explicit(HugePageSize::TwoMib),
);
assert_eq!(f.huge_page_region_count(), 0);
}
}