1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
extern crate libc; use std::io; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[repr(i32)] pub enum AccessPattern { Normal = libc::MADV_NORMAL, Sequential = libc::MADV_SEQUENTIAL, Random = libc::MADV_RANDOM, DontNeed = libc::MADV_DONTNEED, WillNeed = libc::MADV_WILLNEED, } /// Advise the operating system on the access pattern of this data. On unix-like systems this can be /// used to allow the operating system to page memory in and out more efficiently. This is used /// extensively by allocators, and will only improve performance in real programs in rare /// circumstances. /// /// On Windows and other non-unix systems this is compiled into a no-op. As far as I can tell /// Windows has no equivalent API. /// /// ## Example /// /// ```rust /// use madvise::{AccessPattern, AdviseMemory}; /// let mut my_vec = vec![0; 1024]; /// my_vec.advise_memory_access(AccessPattern::Sequential).expect("Advisory failed"); /// for i in &mut my_vec { /// *i += 1; /// } /// ``` pub trait AdviseMemory { fn advise_memory_access(&self, advice: AccessPattern) -> io::Result<()>; } /// Raw advise wrapper with proper error handling. This enforces the same contract as /// `libc::madvise`. Specifically, `ptr` must be non-null and the data between `ptr` and `ptr + len` /// must be initialized. /// /// ## Example /// /// ```rust /// use madvise::{AccessPattern, madvise}; /// use std::mem; /// /// struct BigStruct([u8; 1024]); /// /// let mut heap_allocated_big_struct = Box::new(BigStruct([0; 1024])); /// unsafe { /// madvise( /// Box::as_ref(&heap_allocated_big_struct) as *const BigStruct as *const u8, /// mem::size_of::<BigStruct>(), /// AccessPattern::Sequential /// ).expect("Advisory failed"); /// } /// /// for i in heap_allocated_big_struct.0.iter_mut() { /// *i += 1 /// } /// ``` pub unsafe fn madvise(ptr: *const u8, len: usize, advice: AccessPattern) -> io::Result<()> { let result = libc::madvise(ptr as *mut libc::c_void, len, advice as libc::c_int); if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) } } #[cfg(unix)] impl AdviseMemory for [u8] { fn advise_memory_access(&self, advice: AccessPattern) -> io::Result<()> { unsafe { madvise(self.as_ptr(), self.len(), advice) } } } #[cfg(not(unix))] impl AdviseMemory for [u8] { fn advise_memory_access(&self, _: AccessPattern) -> io::Result<()> { Ok(()) } } #[cfg(test)] mod tests { #[test] fn it_works() {} }