From 3c71286cebd43b49e87449490608024e6b05596b Mon Sep 17 00:00:00 2001 From: ollie <72926894+ollie-etl@users.noreply.github.com> Date: Tue, 10 Oct 2023 12:25:11 +0100 Subject: [PATCH] Add huge pages support. --- CHANGELOG.md | 4 ++++ README.md | 2 +- src/lib.rs | 28 +++++++++++++++++++++++++++- src/stub.rs | 2 +- src/unix.rs | 33 ++++++++++++++++++++++++++++++--- src/windows.rs | 7 ++++++- 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99137b85..12a71e72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed +- Added `MmapOptions::huge` method to support mapping hugetlb. Linux only. + [@ollie-etl](https://github.com/ollie-etl) + [@oliverbunting](https://github.com/oliverbunting) ## [0.9.0] - 2023-10-03 ### Changed diff --git a/README.md b/README.md index df0252b1..1a67fa90 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This is a **fork** of the [memmap-rs](https://github.com/danburkert/memmap-rs) c - [x] read-only memory maps - [x] stack support (`MAP_STACK` on unix) - [x] executable memory maps -- [ ] huge page support +- [x] huge page support (linux only) A list of supported/tested targets can be found in [Actions](https://github.com/RazrFalcon/memmap2-rs/actions). diff --git a/src/lib.rs b/src/lib.rs index d6a185d0..3683755c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,6 +140,7 @@ where pub struct MmapOptions { offset: u64, len: Option, + huge: Option, stack: bool, populate: bool, } @@ -281,6 +282,30 @@ impl MmapOptions { self } + /// Configures the anonymous memory map to be allocated using huge pages. + /// + /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// + /// The size of the requested page can be specified in page bits. If not provided, the system + /// default is requested. The requested length should be a multiple of this, or the mapping + /// will fail. + /// + /// This option has no effect on file-backed memory maps. + /// + /// # Example + /// + /// ``` + /// use memmap2::MmapOptions; + /// + /// # fn main() -> std::io::Result<()> { + /// let stack = MmapOptions::new().huge(Some(21)).len(2*1024*1024).map_anon(); + /// # Ok(()) + /// # } + /// ``` + pub fn huge(&mut self, page_bits: Option) -> &mut Self { + self.huge = Some(page_bits.unwrap_or(0)); + self + } /// Populate (prefault) page tables for a mapping. /// /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. @@ -484,7 +509,8 @@ impl MmapOptions { )); } - MmapInner::map_anon(len, self.stack, self.populate).map(|inner| MmapMut { inner }) + MmapInner::map_anon(len, self.stack, self.populate, self.huge) + .map(|inner| MmapMut { inner }) } /// Creates a raw memory map. diff --git a/src/stub.rs b/src/stub.rs index 3c6af0e7..881983eb 100644 --- a/src/stub.rs +++ b/src/stub.rs @@ -36,7 +36,7 @@ impl MmapInner { MmapInner::new() } - pub fn map_anon(_: usize, _: bool, _: bool) -> io::Result { + pub fn map_anon(_: usize, _: bool, _: bool, _: Option) -> io::Result { MmapInner::new() } diff --git a/src/unix.rs b/src/unix.rs index 1df5691e..d137f9bc 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -26,6 +26,24 @@ const MAP_POPULATE: libc::c_int = libc::MAP_POPULATE; #[cfg(not(any(target_os = "linux", target_os = "android")))] const MAP_POPULATE: libc::c_int = 0; +#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))] +const MAP_HUGETLB: libc::c_int = libc::MAP_HUGETLB; + +#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))] +const MAP_HUGE_MASK: libc::c_int = libc::MAP_HUGE_MASK; + +#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))] +const MAP_HUGE_SHIFT: libc::c_int = libc::MAP_HUGE_SHIFT; + +#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "android")))] +const MAP_HUGETLB: libc::c_int = 0; + +#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "android")))] +const MAP_HUGE_MASK: libc::c_int = 0; + +#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "android")))] +const MAP_HUGE_SHIFT: libc::c_int = 0; + #[cfg(any( target_os = "android", all(target_os = "linux", not(target_env = "musl")) @@ -261,15 +279,24 @@ impl MmapInner { } /// Open an anonymous memory map. - pub fn map_anon(len: usize, stack: bool, populate: bool) -> io::Result { + pub fn map_anon( + len: usize, + stack: bool, + populate: bool, + huge: Option, + ) -> io::Result { let stack = if stack { MAP_STACK } else { 0 }; let populate = if populate { MAP_POPULATE } else { 0 }; + let hugetlb = if huge.is_some() { MAP_HUGETLB } else { 0 }; + let offset = huge + .map(|mask| ((mask as u64) & (MAP_HUGE_MASK as u64)) << MAP_HUGE_SHIFT) + .unwrap_or(0); MmapInner::new( len, libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_PRIVATE | libc::MAP_ANON | stack | populate, + libc::MAP_PRIVATE | libc::MAP_ANON | stack | populate | hugetlb, -1, - 0, + offset, ) } diff --git a/src/windows.rs b/src/windows.rs index 53733690..8a870955 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -343,7 +343,12 @@ impl MmapInner { Ok(inner) } - pub fn map_anon(len: usize, _stack: bool, _populate: bool) -> io::Result { + pub fn map_anon( + len: usize, + _stack: bool, + _populate: bool, + _huge: Option, + ) -> io::Result { // Ensure a non-zero length for the underlying mapping let mapped_len = len.max(1); unsafe {