Skip to content

Commit

Permalink
64bit align memory correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Dec 13, 2023
1 parent 8cff0c9 commit 37b5ff9
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 159 deletions.
87 changes: 72 additions & 15 deletions benches/bloomset.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,85 @@
#![feature(test)]
extern crate test;

use rustc_hash::FxHashSet;
use std::collections::HashSet;
use test::{black_box, Bencher};
use toolshed::set::{BloomSet, Set};
use toolshed::Arena;
use test::{Bencher, black_box};
use std::collections::HashSet;
use rustc_hash::FxHashSet;

static WORDS: &[&str] = &[
"ARENA_BLOCK", "Arena", "Cell", "Self", "String", "T", "Vec", "_unchecked", "a",
"alignment", "alloc", "alloc_bytes", "alloc_str", "alloc_str_zero_end", "alloc_string",
"as", "as_bytes", "as_mut_ptr", "as_ptr", "block", "cap", "cell", "const",
"copy_nonoverlapping", "else", "extend_from_slice", "fn", "from_raw_parts", "from_utf",
"get", "grow", "if", "impl", "inline", "into", "into_bytes", "isize", "len",
"len_with_zero", "let", "mem", "mut", "new", "offset", "ptr", "pub", "push",
"replace", "return", "self", "set", "size_of", "slice", "std", "store", "str",
"struct", "temp", "u", "unsafe", "use", "usize", "val", "vec", "with_capacity"
"ARENA_BLOCK",
"Arena",
"Cell",
"Self",
"String",
"T",
"Vec",
"_unchecked",
"a",
"alignment",
"alloc",
"alloc_bytes",
"alloc_str",
"alloc_str_zero_end",
"alloc_string",
"as",
"as_bytes",
"as_mut_ptr",
"as_ptr",
"block",
"cap",
"cell",
"const",
"copy_nonoverlapping",
"else",
"extend_from_slice",
"fn",
"from_raw_parts",
"from_utf",
"get",
"grow",
"if",
"impl",
"inline",
"into",
"into_bytes",
"isize",
"len",
"len_with_zero",
"let",
"mem",
"mut",
"new",
"offset",
"ptr",
"pub",
"push",
"replace",
"return",
"self",
"set",
"size_of",
"slice",
"std",
"store",
"str",
"struct",
"temp",
"u",
"unsafe",
"use",
"usize",
"val",
"vec",
"with_capacity",
];
static SET_WORDS: &[&str] = &["alloc_bytes", "alloc", "Cell", "String", "yetAnother"];

#[bench]
fn set_read(b: &mut Bencher) {
let arena = Arena::new();
let a = &arena;
let a = &arena;
let set = Set::new();

for word in SET_WORDS.iter() {
Expand All @@ -39,7 +96,7 @@ fn set_read(b: &mut Bencher) {
#[bench]
fn set_create(b: &mut Bencher) {
let arena = Arena::new();
let a = &arena;
let a = &arena;

b.iter(|| {
unsafe { a.clear() };
Expand All @@ -56,7 +113,7 @@ fn set_create(b: &mut Bencher) {
#[bench]
fn bloom_set_read(b: &mut Bencher) {
let arena = Arena::new();
let a = &arena;
let a = &arena;
let set = BloomSet::new();

for word in SET_WORDS.iter() {
Expand All @@ -73,7 +130,7 @@ fn bloom_set_read(b: &mut Bencher) {
#[bench]
fn bloom_set_create(b: &mut Bencher) {
let arena = Arena::new();
let a = &arena;
let a = &arena;

b.iter(|| {
unsafe { a.clear() };
Expand Down
75 changes: 66 additions & 9 deletions benches/list.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,76 @@
#![feature(test)]
extern crate test;

use test::{black_box, Bencher};
use toolshed::list::ListBuilder;
use toolshed::Arena;
use test::{Bencher, black_box};

static WORDS: &[&str] = &[
"ARENA_BLOCK", "Arena", "Cell", "Self", "String", "T", "Vec", "_unchecked", "a",
"alignment", "alloc", "alloc_bytes", "alloc_str", "alloc_str_zero_end", "alloc_string",
"as", "as_bytes", "as_mut_ptr", "as_ptr", "block", "cap", "cell", "const",
"copy_nonoverlapping", "else", "extend_from_slice", "fn", "from_raw_parts", "from_utf",
"get", "grow", "if", "impl", "inline", "into", "into_bytes", "isize", "len",
"len_with_zero", "let", "mem", "mut", "new", "offset", "ptr", "pub", "push",
"replace", "return", "self", "set", "size_of", "slice", "std", "store", "str",
"struct", "temp", "u", "unsafe", "use", "usize", "val", "vec", "with_capacity"
"ARENA_BLOCK",
"Arena",
"Cell",
"Self",
"String",
"T",
"Vec",
"_unchecked",
"a",
"alignment",
"alloc",
"alloc_bytes",
"alloc_str",
"alloc_str_zero_end",
"alloc_string",
"as",
"as_bytes",
"as_mut_ptr",
"as_ptr",
"block",
"cap",
"cell",
"const",
"copy_nonoverlapping",
"else",
"extend_from_slice",
"fn",
"from_raw_parts",
"from_utf",
"get",
"grow",
"if",
"impl",
"inline",
"into",
"into_bytes",
"isize",
"len",
"len_with_zero",
"let",
"mem",
"mut",
"new",
"offset",
"ptr",
"pub",
"push",
"replace",
"return",
"self",
"set",
"size_of",
"slice",
"std",
"store",
"str",
"struct",
"temp",
"u",
"unsafe",
"use",
"usize",
"val",
"vec",
"with_capacity",
];

#[bench]
Expand Down
87 changes: 45 additions & 42 deletions src/arena.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Module containing the `Arena` and `Uninitialized` structs. For convenience the
//! `Arena` is exported at the root of the crate.
use std::mem::size_of;
use std::ops::Deref;
use std::cell::Cell;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::mem::size_of;
use std::ops::Deref;

const ARENA_BLOCK: usize = 64 * 1024;

Expand Down Expand Up @@ -198,23 +198,27 @@ impl Arena {
///
/// The slice will be at maximum length `n`, further elements of the iterator ignored and not evaluated.
/// If the iterator yields less than `n` elements, a shorter slice will simply be returned.
pub fn alloc_lazy_slice<'arena, T, I: Iterator<Item=T>>(&'arena self, vals: I, n: usize) -> &'arena [T] {
// Grab space for `n` elements even if it may turn out we have to walk it back
let ptr = self.require(n * size_of::<T>()) as *mut T;
let mut i: usize = 0;
pub fn alloc_lazy_slice<'arena, T, I: Iterator<Item = T>>(
&'arena self,
vals: I,
n: usize,
) -> &'arena [T] {
// Grab space for `n` elements even if it may turn out we have to walk it back
let ptr = self.require(n * size_of::<T>()) as *mut T;
let mut i: usize = 0;

unsafe {
use std::slice::from_raw_parts;
unsafe {
use std::slice::from_raw_parts;

for val in vals.take(n) {
*ptr.offset(i as isize) = val;
i += 1;
for val in vals.take(n) {
*ptr.offset(i as isize) = val;
i += 1;
}
// Now fix the slice length and arena offset
let diff = n - i;
self.reset_to(self.offset() - diff * size_of::<T>());
from_raw_parts(ptr, i)
}
// Now fix the slice length and arena offset
let diff = n - i;
self.reset_to( self.offset() - diff * size_of::<T>() );
from_raw_parts(ptr, i)
}
}

/// Put a `Vec<T>` on the arena without reallocating.
Expand All @@ -227,9 +231,8 @@ impl Arena {

mem::forget(val);

let out = self.alloc_byte_vec(unsafe {
Vec::from_raw_parts(ptr as _, 0, cap * size_of::<T>())
});
let out =
self.alloc_byte_vec(unsafe { Vec::from_raw_parts(ptr as _, 0, cap * size_of::<T>()) });

unsafe { slice::from_raw_parts(out as _, len) }
}
Expand All @@ -241,7 +244,7 @@ impl Arena {
T: Sized + Copy + 'input,
{
match vals {
Cow::Owned(vec) => self.alloc_vec(vec),
Cow::Owned(vec) => self.alloc_vec(vec),
Cow::Borrowed(slice) => self.alloc_slice(slice),
}
}
Expand Down Expand Up @@ -286,8 +289,8 @@ impl Arena {
let ptr = self.alloc_byte_vec(val.into_bytes());

unsafe {
use std::str::from_utf8_unchecked;
use std::slice::from_raw_parts;
use std::str::from_utf8_unchecked;

from_utf8_unchecked(from_raw_parts(ptr, len))
}
Expand Down Expand Up @@ -315,11 +318,11 @@ impl Arena {
return self.alloc_bytes(size);
}

let size = match size % size_of::<usize>() {
let align = std::mem::align_of_val(&5i64);
let size = match size % align {
0 => size,
n => size + (size_of::<usize>() - n),
n => size + (align - n),
};

let offset = self.offset.get();
let cap = offset + size;

Expand Down Expand Up @@ -447,20 +450,20 @@ mod test {

#[test]
fn alloc_lazy_slices() {
let arena = Arena::new();
let nums: [u32; 6] = [1, 2, 3, 4, 5, 1000];
let big_nums: [u32; 6] = [100, 200, 300, 400, 500, 1050];
let arena = Arena::new();
let nums: [u32; 6] = [1, 2, 3, 4, 5, 1000];
let big_nums: [u32; 6] = [100, 200, 300, 400, 500, 1050];

// Put the whole array in the arena
let all_nums = arena.alloc_lazy_slice(nums.iter().map(|x| *x), 6);
// Truncate it using the `n` argument
let trunc_nums = arena.alloc_lazy_slice(big_nums.iter().map(|x| *x), 3);
// Put a whole array of half the nums in the arena
let half_nums = arena.alloc_lazy_slice(nums[0..3].iter().map(|x| *x), 6);
// Put the whole array in the arena
let all_nums = arena.alloc_lazy_slice(nums.iter().map(|x| *x), 6);
// Truncate it using the `n` argument
let trunc_nums = arena.alloc_lazy_slice(big_nums.iter().map(|x| *x), 3);
// Put a whole array of half the nums in the arena
let half_nums = arena.alloc_lazy_slice(nums[0..3].iter().map(|x| *x), 6);

assert!(nums.iter().eq(all_nums.iter()));
assert!(nums[0..3].iter().eq(half_nums.iter()));
assert!(big_nums[0..3].iter().eq(trunc_nums.iter()));
assert!(nums.iter().eq(all_nums.iter()));
assert!(nums[0..3].iter().eq(half_nums.iter()));
assert!(big_nums[0..3].iter().eq(trunc_nums.iter()));
}

#[test]
Expand All @@ -470,7 +473,10 @@ mod test {
assert_eq!(arena.alloc_slice(b"foo"), b"foo");
assert_eq!(arena.offset.get(), 8);

assert_eq!(arena.alloc_slice(b"doge to the moon!"), b"doge to the moon!");
assert_eq!(
arena.alloc_slice(b"doge to the moon!"),
b"doge to the moon!"
);
assert_eq!(arena.offset.get(), 32);
}

Expand All @@ -492,10 +498,7 @@ mod test {
let allocated = unsafe { ::std::slice::from_raw_parts(nts.as_ptr(), 12) };

assert_eq!(arena.offset.get(), 16);
assert_eq!(
allocated,
"abcdefghijk\u{0}".as_bytes(),
);
assert_eq!(allocated, "abcdefghijk\u{0}".as_bytes(),);

assert_eq!(&**nts, "abcdefghijk");
}
Expand Down
Loading

0 comments on commit 37b5ff9

Please sign in to comment.