Skip to content
This repository was archived by the owner on Aug 25, 2025. It is now read-only.

Commit f0a48f6

Browse files
committed
Add a fixed-sized backend for experimental use with non-traditional targets
1 parent 36294af commit f0a48f6

File tree

9 files changed

+156
-37
lines changed

9 files changed

+156
-37
lines changed

test.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ time cargo test --release --features "extra_assertions size_classes"
1515
time cargo test --release --features "extra_assertions"
1616
time cargo test --release --features "size_classes"
1717
time cargo test --release
18+
19+
time cargo test --release --features "static_array_backend extra_assertions size_classes"
20+
time cargo test --release --features "static_array_backend extra_assertions"
21+
time cargo test --release --features "static_array_backend size_classes"
22+
time cargo test --release --features "static_array_backend"
1823
cd -

test/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.1.0"
77
rand = "0.4.2"
88
quickcheck = "0.6.0"
99
histo = "0.1.0"
10+
cfg-if = "0.1.2"
1011

1112
[dependencies.wee_alloc]
1213
path = "../wee_alloc"
@@ -16,3 +17,4 @@ features = ["use_std_for_test_debugging"]
1617
[features]
1718
size_classes = ["wee_alloc/size_classes"]
1819
extra_assertions = ["wee_alloc/extra_assertions"]
20+
static_array_backend = ["wee_alloc/static_array_backend"]

test/benches/bench.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::io;
88
use wee_alloc_test::*;
99

1010
macro_rules! bench_trace {
11-
( $name:ident, $trace:expr ) => {
11+
($name:ident, $trace:expr) => {
1212
#[bench]
1313
#[cfg(not(feature = "extra_assertions"))]
1414
fn $name(b: &mut test::Bencher) {
@@ -18,7 +18,10 @@ macro_rules! bench_trace {
1818
let stdout = io::stdout();
1919
let _stdout = stdout.lock();
2020

21-
println!("################## {} ##################", stringify!($name));
21+
println!(
22+
"################## {} ##################",
23+
stringify!($name)
24+
);
2225
println!("#");
2326
println!("# Allocations by log2(Size)");
2427
println!("#");
@@ -34,15 +37,18 @@ macro_rules! bench_trace {
3437
operations.run_with_allocator(a);
3538
});
3639
}
37-
}
40+
};
3841
}
3942

4043
bench_trace!(bench_trace_cpp_demangle, "../traces/cpp-demangle.trace");
4144
bench_trace!(bench_trace_dogfood, "../traces/dogfood.trace");
4245
bench_trace!(bench_trace_ffmpeg, "../traces/ffmpeg.trace");
4346
bench_trace!(bench_trace_find, "../traces/find.trace");
4447
bench_trace!(bench_trace_gcc_hello, "../traces/gcc-hello.trace");
45-
bench_trace!(bench_trace_grep_random_data, "../traces/grep-random-data.trace");
48+
bench_trace!(
49+
bench_trace_grep_random_data,
50+
"../traces/grep-random-data.trace"
51+
);
4652
bench_trace!(bench_trace_grep_recursive, "../traces/grep-recursive.trace");
4753
bench_trace!(bench_trace_ls, "../traces/ls.trace");
4854
bench_trace!(bench_trace_source_map, "../traces/source-map.trace");

test/src/lib.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ extern crate alloc;
44
extern crate histo;
55
#[macro_use]
66
extern crate quickcheck;
7+
#[macro_use]
8+
extern crate cfg_if;
79
extern crate rand;
810
extern crate wee_alloc;
911

@@ -257,10 +259,10 @@ impl Operations {
257259
let handle2 = thread::spawn(move || ops2.run_with_allocator(&WEE));
258260
let handle3 = thread::spawn(move || ops3.run_with_allocator(&WEE));
259261

260-
handle0.join().unwrap();
261-
handle1.join().unwrap();
262-
handle2.join().unwrap();
263-
handle3.join().unwrap();
262+
handle0.join().expect("Thread 0 Failed");
263+
handle1.join().expect("Thread 1 Failed");
264+
handle2.join().expect("Thread 2 Failed");
265+
handle3.join().expect("Thread 3 Failed");
264266
}
265267

266268
pub fn run_with_allocator<A: Alloc>(&self, mut a: A) {
@@ -344,12 +346,17 @@ macro_rules! run_quickchecks {
344346
// with each other.
345347
run_quickchecks!(quickchecks_0);
346348
run_quickchecks!(quickchecks_1);
347-
run_quickchecks!(quickchecks_2);
348-
run_quickchecks!(quickchecks_3);
349-
run_quickchecks!(quickchecks_4);
350-
run_quickchecks!(quickchecks_5);
351-
run_quickchecks!(quickchecks_6);
352-
run_quickchecks!(quickchecks_7);
349+
// Limit the extent of the stress testing for the limited-size static backend
350+
cfg_if! {
351+
if #[cfg(not(feature = "static_array_backend"))] {
352+
run_quickchecks!(quickchecks_2);
353+
run_quickchecks!(quickchecks_3);
354+
run_quickchecks!(quickchecks_4);
355+
run_quickchecks!(quickchecks_5);
356+
run_quickchecks!(quickchecks_6);
357+
run_quickchecks!(quickchecks_7);
358+
}
359+
}
353360

354361
#[test]
355362
fn multi_threaded_quickchecks() {
@@ -389,7 +396,10 @@ test_trace!(test_trace_dogfood, "../traces/dogfood.trace");
389396
test_trace!(test_trace_ffmpeg, "../traces/ffmpeg.trace");
390397
test_trace!(test_trace_find, "../traces/find.trace");
391398
test_trace!(test_trace_gcc_hello, "../traces/gcc-hello.trace");
392-
test_trace!(test_trace_grep_random_data, "../traces/grep-random-data.trace");
399+
test_trace!(
400+
test_trace_grep_random_data,
401+
"../traces/grep-random-data.trace"
402+
);
393403
test_trace!(test_trace_grep_recursive, "../traces/grep-recursive.trace");
394404
test_trace!(test_trace_ls, "../traces/ls.trace");
395405
test_trace!(test_trace_source_map, "../traces/source-map.trace");
@@ -408,13 +418,7 @@ fn regression_test_1() {
408418

409419
#[test]
410420
fn regression_test_2() {
411-
Operations(vec![
412-
Alloc(168),
413-
Free(0),
414-
Alloc(0),
415-
Alloc(168),
416-
Free(2),
417-
]).run_single_threaded();
421+
Operations(vec![Alloc(168), Free(0), Alloc(0), Alloc(168), Free(2)]).run_single_threaded();
418422
}
419423

420424
#[test]
@@ -472,15 +476,17 @@ fn smoke() {
472476
let mut a = &wee_alloc::WeeAlloc::INIT;
473477
unsafe {
474478
let layout = Layout::new::<u8>();
475-
let ptr = a.alloc(layout.clone()).unwrap();
479+
let ptr = a.alloc(layout.clone())
480+
.expect("Should be able to alloc a fresh Layout clone");
476481
{
477482
let ptr = ptr.as_ptr() as *mut u8;
478483
*ptr = 9;
479484
assert_eq!(*ptr, 9);
480485
}
481486
a.dealloc(ptr, layout.clone());
482487

483-
let ptr = a.alloc(layout.clone()).unwrap();
488+
let ptr = a.alloc(layout.clone())
489+
.expect("Should be able to alloc from a second clone");
484490
{
485491
let ptr = ptr.as_ptr() as *mut u8;
486492
*ptr = 10;
@@ -490,9 +496,10 @@ fn smoke() {
490496
}
491497
}
492498

493-
// This takes too long with our extra assertion checks enabled.
499+
// This takes too long with our extra assertion checks enabled,
500+
// and the fixed-sized static array backend is too small.
494501
#[test]
495-
#[cfg(not(feature = "extra_assertions"))]
502+
#[cfg(not(any(feature = "extra_assertions", feature = "static_array_backend")))]
496503
fn stress() {
497504
use rand::Rng;
498505
use std::cmp;

wee_alloc/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,18 @@ size_classes = []
2323
# This is for internal use only.
2424
use_std_for_test_debugging = []
2525

26+
static_array_backend = []
27+
2628
[dependencies]
2729
memory_units = "0.4.0"
2830
cfg-if = "0.1.2"
2931
unreachable = "1.0.0"
3032

33+
[dependencies.spin]
34+
version = "0.4"
35+
default-features = false
36+
features = ["const_fn"]
37+
3138
[target.'cfg(all(unix, not(target_arch = "wasm32")))'.dependencies.libc]
3239
default-features = false
3340
version = "0.2"

wee_alloc/src/imp_static_array.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use const_init::ConstInit;
2+
use core::alloc::{AllocErr, Opaque};
3+
use core::cell::UnsafeCell;
4+
#[cfg(feature = "extra_assertions")]
5+
use core::cell::Cell;
6+
use core::ptr::NonNull;
7+
use memory_units::{Bytes, Pages};
8+
use spin::Mutex;
9+
10+
const SCRATCH_LEN_BYTES: usize = 1024 * 1024 * 32;
11+
static mut SCRATCH_HEAP: [u8; SCRATCH_LEN_BYTES] = [0; SCRATCH_LEN_BYTES];
12+
static mut OFFSET: Mutex<usize> = Mutex::new(0);
13+
14+
pub(crate) unsafe fn alloc_pages(pages: Pages) -> Result<NonNull<Opaque>, AllocErr> {
15+
let bytes: Bytes = pages.into();
16+
let mut offset = OFFSET.lock();
17+
let end = bytes.0 + *offset;
18+
if end < SCRATCH_LEN_BYTES {
19+
let ptr = SCRATCH_HEAP[*offset..end].as_mut_ptr() as *mut u8 as *mut Opaque;
20+
*offset = end;
21+
NonNull::new(ptr).ok_or_else(|| AllocErr)
22+
} else {
23+
Err(AllocErr)
24+
}
25+
}
26+
27+
pub(crate) struct Exclusive<T> {
28+
lock: Mutex<bool>,
29+
inner: UnsafeCell<T>,
30+
31+
#[cfg(feature = "extra_assertions")]
32+
in_use: Cell<bool>,
33+
}
34+
35+
impl<T: ConstInit> ConstInit for Exclusive<T> {
36+
const INIT: Self = Exclusive {
37+
lock: Mutex::new(false),
38+
inner: UnsafeCell::new(T::INIT),
39+
40+
#[cfg(feature = "extra_assertions")]
41+
in_use: Cell::new(false),
42+
};
43+
}
44+
45+
extra_only! {
46+
fn assert_not_in_use<T>(excl: &Exclusive<T>) {
47+
assert!(!excl.in_use.get(), "`Exclusive<T>` is not re-entrant");
48+
}
49+
}
50+
51+
extra_only! {
52+
fn set_in_use<T>(excl: &Exclusive<T>) {
53+
excl.in_use.set(true);
54+
}
55+
}
56+
57+
extra_only! {
58+
fn set_not_in_use<T>(excl: &Exclusive<T>) {
59+
excl.in_use.set(false);
60+
}
61+
}
62+
63+
impl<T> Exclusive<T> {
64+
/// Get exclusive, mutable access to the inner value.
65+
///
66+
/// # Safety
67+
///
68+
/// It is the callers' responsibility to ensure that `f` does not re-enter
69+
/// this method for this `Exclusive` instance.
70+
//
71+
// XXX: If we don't mark this function inline, then it won't be, and the
72+
// code size also blows up by about 200 bytes.
73+
#[inline]
74+
pub(crate) unsafe fn with_exclusive_access<'a, F, U>(&'a self, f: F) -> U
75+
where
76+
F: FnOnce(&'a mut T) -> U,
77+
{
78+
let _l = self.lock.lock();
79+
assert_not_in_use(self);
80+
set_in_use(self);
81+
let data = &mut *self.inner.get();
82+
let result = f(data);
83+
set_not_in_use(self);
84+
result
85+
}
86+
}

wee_alloc/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ extern crate alloc;
224224

225225
#[cfg(feature = "use_std_for_test_debugging")]
226226
extern crate core;
227+
#[cfg(feature = "static_array_backend")]
228+
extern crate spin;
227229

228230
extern crate memory_units;
229231
extern crate unreachable;
@@ -232,7 +234,10 @@ extern crate unreachable;
232234
mod extra_assert;
233235

234236
cfg_if! {
235-
if #[cfg(target_arch = "wasm32")] {
237+
if #[cfg(feature = "static_array_backend")]{
238+
mod imp_static_array;
239+
use imp_static_array as imp;
240+
} else if #[cfg(target_arch = "wasm32")] {
236241
mod imp_wasm32;
237242
use imp_wasm32 as imp;
238243
} else if #[cfg(unix)] {
@@ -946,7 +951,9 @@ unsafe fn alloc_first_fit<'a>(
946951

947952
if let Some(allocated) = current.try_alloc(previous, size, align, policy) {
948953
assert_aligned_to(allocated.data(), align);
949-
return Some(unchecked_unwrap(NonNull::new(allocated.data() as *mut Opaque)));
954+
return Some(unchecked_unwrap(
955+
NonNull::new(allocated.data() as *mut Opaque),
956+
));
950957
}
951958

952959
None
@@ -1055,7 +1062,7 @@ impl<'a> WeeAlloc<'a> {
10551062

10561063
unsafe impl<'a, 'b> Alloc for &'b WeeAlloc<'a>
10571064
where
1058-
'a: 'b
1065+
'a: 'b,
10591066
{
10601067
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
10611068
let size = Bytes(layout.size());

wee_alloc/src/neighbors.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,12 @@ where
185185

186186
#[inline]
187187
pub fn next(&self) -> Option<&'a T> {
188-
unsafe {
189-
T::next_checked(self, self.next_unchecked())
190-
}
188+
unsafe { T::next_checked(self, self.next_unchecked()) }
191189
}
192190

193191
#[inline]
194192
pub fn prev(&self) -> Option<&'a T> {
195-
unsafe {
196-
T::prev_checked(self, self.prev_unchecked())
197-
}
193+
unsafe { T::prev_checked(self, self.prev_unchecked()) }
198194
}
199195
}
200196

wee_alloc/src/size_classes.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{alloc_with_refill, AllocPolicy, CellHeader, FreeCell, LargeAllocPolicy};
2-
use core::alloc::AllocErr;
32
use const_init::ConstInit;
3+
use core::alloc::AllocErr;
44
use core::cell::Cell;
55
use core::cmp;
66
use imp;
@@ -75,7 +75,10 @@ where
7575
self as &AllocPolicy,
7676
);
7777
let next_cell = (new_cell.as_ptr() as *const u8).offset(new_cell_size.0 as isize);
78-
(*free_cell).header.neighbors.set_next(next_cell as *const CellHeader);
78+
(*free_cell)
79+
.header
80+
.neighbors
81+
.set_next(next_cell as *const CellHeader);
7982
CellHeader::set_next_cell_is_invalid(&(*free_cell).header.neighbors);
8083
Ok(free_cell)
8184
}

0 commit comments

Comments
 (0)