Results and polishing.
This commit is contained in:
parent
a0776876c1
commit
9f4cc26c02
|
@ -3,7 +3,7 @@
|
||||||
//! This implementation uses `mmap` on POSIX systems (and should use `VirtualAlloc` on windows).
|
//! This implementation uses `mmap` on POSIX systems (and should use `VirtualAlloc` on windows).
|
||||||
//! There are possibilities to improve the performance for the reallocating case by reserving
|
//! There are possibilities to improve the performance for the reallocating case by reserving
|
||||||
//! memory up to maximum. This might be a problem for systems that don't have a lot of virtual
|
//! memory up to maximum. This might be a problem for systems that don't have a lot of virtual
|
||||||
//! memory.
|
//! memory (i.e. 32-bit platforms).
|
||||||
|
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
@ -20,9 +20,20 @@ struct Mmap {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mmap {
|
impl Mmap {
|
||||||
fn new(len: usize) -> Self {
|
/// Create a new mmap mapping
|
||||||
assert!(len < isize::max_value() as usize);
|
///
|
||||||
assert!(len > 0);
|
/// Returns `Err` if:
|
||||||
|
/// - `len` should not exceed `isize::max_value()`
|
||||||
|
/// - `len` should be greater than 0.
|
||||||
|
/// - `mmap` returns an error (almost certainly means out of memory).
|
||||||
|
fn new(len: usize) -> Result<Self, &'static str> {
|
||||||
|
if len >= isize::max_value() as usize {
|
||||||
|
return Err("`len` should not exceed `isize::max_value()`");
|
||||||
|
}
|
||||||
|
if len == 0 {
|
||||||
|
return Err("`len` should be greater than 0");
|
||||||
|
}
|
||||||
|
|
||||||
let ptr_or_err = unsafe {
|
let ptr_or_err = unsafe {
|
||||||
// Safety Proof:
|
// Safety Proof:
|
||||||
// There are not specific safety proofs are required for this call, since the call
|
// There are not specific safety proofs are required for this call, since the call
|
||||||
|
@ -48,15 +59,19 @@ impl Mmap {
|
||||||
};
|
};
|
||||||
|
|
||||||
match ptr_or_err as usize {
|
match ptr_or_err as usize {
|
||||||
// `mmap` shouldn't return 0 since it has a special meaning.
|
// `mmap` returns -1 in case of an error.
|
||||||
x if x == 0 || x as isize == -1 => panic!(),
|
// `mmap` shouldn't return 0 since it has a special meaning for compilers.
|
||||||
|
//
|
||||||
|
// With the current parameters, the error can only be returned in case of insufficient
|
||||||
|
// memory.
|
||||||
|
x if x == 0 || x as isize == -1 => Err("mmap returned error"),
|
||||||
_ => {
|
_ => {
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
// Safety Proof:
|
// Safety Proof:
|
||||||
// the ptr cannot be null as checked within the enclosing match.
|
// the ptr cannot be null as checked within the enclosing match.
|
||||||
NonNull::new_unchecked(ptr_or_err as *mut u8)
|
NonNull::new_unchecked(ptr_or_err as *mut u8)
|
||||||
};
|
};
|
||||||
Self { ptr, len }
|
Ok(Self { ptr, len })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,19 +123,23 @@ pub struct ByteBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ByteBuf {
|
impl ByteBuf {
|
||||||
pub fn new(len: usize) -> Self {
|
pub fn new(len: usize) -> Result<Self, &'static str> {
|
||||||
let mmap = if len == 0 { None } else { Some(Mmap::new(len)) };
|
let mmap = if len == 0 {
|
||||||
Self { mmap }
|
None
|
||||||
|
} else {
|
||||||
|
Some(Mmap::new(len)?)
|
||||||
|
};
|
||||||
|
Ok(Self { mmap })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn realloc(&mut self, new_len: usize) {
|
pub fn realloc(&mut self, new_len: usize) -> Result<(), &'static str> {
|
||||||
let new_mmap = if new_len == 0 {
|
let new_mmap = if new_len == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
if self.len() == 0 {
|
if self.len() == 0 {
|
||||||
Some(Mmap::new(new_len))
|
Some(Mmap::new(new_len)?)
|
||||||
} else {
|
} else {
|
||||||
let mut new_mmap = Mmap::new(new_len);
|
let mut new_mmap = Mmap::new(new_len)?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let src = self.mmap.as_ref().unwrap().as_slice();
|
let src = self.mmap.as_ref().unwrap().as_slice();
|
||||||
|
@ -131,8 +150,8 @@ impl ByteBuf {
|
||||||
Some(new_mmap)
|
Some(new_mmap)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.mmap = new_mmap;
|
self.mmap = new_mmap;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
|
@ -149,4 +168,23 @@ impl ByteBuf {
|
||||||
.map(|m| m.as_slice_mut())
|
.map(|m| m.as_slice_mut())
|
||||||
.unwrap_or(&mut [])
|
.unwrap_or(&mut [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn erase(&mut self) -> Result<(), &'static str> {
|
||||||
|
let cur_len = match self.mmap {
|
||||||
|
// Nothing to do here...
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(Mmap { len: cur_len, .. }) => cur_len,
|
||||||
|
};
|
||||||
|
|
||||||
|
// The order is important.
|
||||||
|
//
|
||||||
|
// 1. First we clear, and thus drop, the current mmap if any.
|
||||||
|
// 2. And then we create a new one.
|
||||||
|
//
|
||||||
|
// Otherwise we double the peak memory consumption.
|
||||||
|
self.mmap = None;
|
||||||
|
self.mmap = Some(Mmap::new(cur_len)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,12 +79,6 @@ mod bytebuf;
|
||||||
|
|
||||||
use self::bytebuf::ByteBuf;
|
use self::bytebuf::ByteBuf;
|
||||||
|
|
||||||
// mod rust_alloc as byte_buf;
|
|
||||||
// use self::rust_alloc::ByteBuf;
|
|
||||||
|
|
||||||
// mod vec_backed;
|
|
||||||
// use self::vec_backed::ByteBuf;
|
|
||||||
|
|
||||||
struct CheckedRegion {
|
struct CheckedRegion {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
size: usize,
|
size: usize,
|
||||||
|
@ -141,22 +135,24 @@ impl MemoryInstance {
|
||||||
validation::validate_memory(initial_u32, maximum_u32).map_err(Error::Memory)?;
|
validation::validate_memory(initial_u32, maximum_u32).map_err(Error::Memory)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let memory = MemoryInstance::new(initial, maximum);
|
let memory = MemoryInstance::new(initial, maximum)?;
|
||||||
Ok(MemoryRef(Rc::new(memory)))
|
Ok(MemoryRef(Rc::new(memory)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create new linear memory instance.
|
/// Create new linear memory instance.
|
||||||
fn new(initial: Pages, maximum: Option<Pages>) -> Self {
|
fn new(initial: Pages, maximum: Option<Pages>) -> Result<Self, Error> {
|
||||||
let limits = ResizableLimits::new(initial.0 as u32, maximum.map(|p| p.0 as u32));
|
let limits = ResizableLimits::new(initial.0 as u32, maximum.map(|p| p.0 as u32));
|
||||||
|
|
||||||
let initial_size: Bytes = initial.into();
|
let initial_size: Bytes = initial.into();
|
||||||
MemoryInstance {
|
Ok(MemoryInstance {
|
||||||
limits: limits,
|
limits: limits,
|
||||||
buffer: RefCell::new(ByteBuf::new(initial_size.0)),
|
buffer: RefCell::new(
|
||||||
|
ByteBuf::new(initial_size.0).map_err(|err| Error::Memory(err.to_string()))?,
|
||||||
|
),
|
||||||
initial: initial,
|
initial: initial,
|
||||||
current_size: Cell::new(initial_size.0),
|
current_size: Cell::new(initial_size.0),
|
||||||
maximum: maximum,
|
maximum: maximum,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return linear memory limits.
|
/// Return linear memory limits.
|
||||||
|
@ -290,8 +286,12 @@ impl MemoryInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_buffer_length: Bytes = new_size.into();
|
let new_buffer_length: Bytes = new_size.into();
|
||||||
|
self.buffer
|
||||||
|
.borrow_mut()
|
||||||
|
.realloc(new_buffer_length.0)
|
||||||
|
.map_err(|err| Error::Memory(err.to_string()))?;
|
||||||
|
|
||||||
self.current_size.set(new_buffer_length.0);
|
self.current_size.set(new_buffer_length.0);
|
||||||
self.buffer.borrow_mut().realloc(new_buffer_length.0);
|
|
||||||
|
|
||||||
Ok(size_before_grow)
|
Ok(size_before_grow)
|
||||||
}
|
}
|
||||||
|
@ -499,12 +499,14 @@ impl MemoryInstance {
|
||||||
self.clear(offset, 0, len)
|
self.clear(offset, 0, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set every byte in the entire linear memory to 0.
|
/// Set every byte in the entire linear memory to 0, preserving its size.
|
||||||
///
|
///
|
||||||
/// Might be useful for some optimization shenanigans.
|
/// Might be useful for some optimization shenanigans.
|
||||||
pub fn erase(&self) {
|
pub fn erase(&self) -> Result<(), Error> {
|
||||||
let cur_size = self.buffer.borrow().len();
|
self.buffer
|
||||||
*self.buffer.borrow_mut() = ByteBuf::new(cur_size);
|
.borrow_mut()
|
||||||
|
.erase()
|
||||||
|
.map_err(|err| Error::Memory(err.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,30 +520,22 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn alloc() {
|
fn alloc() {
|
||||||
#[cfg(target_pointer_width = "64")]
|
let mut fixtures = vec![
|
||||||
let fixtures = &[
|
|
||||||
(0, None, true),
|
(0, None, true),
|
||||||
(0, Some(0), true),
|
(0, Some(0), true),
|
||||||
(1, None, true),
|
(1, None, true),
|
||||||
(1, Some(1), true),
|
(1, Some(1), true),
|
||||||
(0, Some(1), true),
|
(0, Some(1), true),
|
||||||
(1, Some(0), false),
|
(1, Some(0), false),
|
||||||
(0, Some(65536), true),
|
|
||||||
// TODO: Only use it for rust-alloc/mmap
|
|
||||||
// (65536, Some(65536), true),
|
|
||||||
// (65536, Some(0), false),
|
|
||||||
// (65536, None, true),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
let fixtures = &[
|
fixtures.extend(&[
|
||||||
(0, None, true),
|
|
||||||
(0, Some(0), true),
|
(65536, Some(65536), true),
|
||||||
(1, None, true),
|
(65536, Some(0), false),
|
||||||
(1, Some(1), true),
|
(65536, None, true),
|
||||||
(0, Some(1), true),
|
]);
|
||||||
(1, Some(0), false),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (index, &(initial, maybe_max, expected_ok)) in fixtures.iter().enumerate() {
|
for (index, &(initial, maybe_max, expected_ok)) in fixtures.iter().enumerate() {
|
||||||
let initial: Pages = Pages(initial);
|
let initial: Pages = Pages(initial);
|
||||||
|
@ -563,7 +557,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_memory(initial_content: &[u8]) -> MemoryInstance {
|
fn create_memory(initial_content: &[u8]) -> MemoryInstance {
|
||||||
let mem = MemoryInstance::new(Pages(1), Some(Pages(1)));
|
let mem = MemoryInstance::new(Pages(1), Some(Pages(1))).unwrap();
|
||||||
mem.set(0, initial_content)
|
mem.set(0, initial_content)
|
||||||
.expect("Successful initialize the memory");
|
.expect("Successful initialize the memory");
|
||||||
mem
|
mem
|
||||||
|
@ -676,7 +670,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_into() {
|
fn get_into() {
|
||||||
let mem = MemoryInstance::new(Pages(1), None);
|
let mem = MemoryInstance::new(Pages(1), None).unwrap();
|
||||||
mem.set(6, &[13, 17, 129])
|
mem.set(6, &[13, 17, 129])
|
||||||
.expect("memory set should not fail");
|
.expect("memory set should not fail");
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,15 @@ pub struct ByteBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ByteBuf {
|
impl ByteBuf {
|
||||||
pub fn new(len: usize) -> Self {
|
pub fn new(len: usize) -> Result<Self, &'static str> {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
buf.resize(len, 0u8);
|
buf.resize(len, 0u8);
|
||||||
Self {
|
Ok(Self { buf })
|
||||||
buf,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn realloc(&mut self, new_len: usize) {
|
pub fn realloc(&mut self, new_len: usize) -> Result<(), &'static str> {
|
||||||
self.buf.resize(new_len, 0u8);
|
self.buf.resize(new_len, 0u8);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
|
@ -30,4 +29,11 @@ impl ByteBuf {
|
||||||
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||||
self.buf.as_mut()
|
self.buf.as_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn erase(&mut self) -> Result<(), &'static str> {
|
||||||
|
for v in &mut self.buf {
|
||||||
|
*v = 0;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue