Skip to content

Commit

Permalink
thinpool and resize
Browse files Browse the repository at this point in the history
  • Loading branch information
wsm25 committed Apr 7, 2024
1 parent 848f30a commit 07afd8c
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 19 deletions.
2 changes: 1 addition & 1 deletion toys-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ criterion = { version = "0.4"}

[[bench]]
name = "benchmark"
harness = false
harness = false
25 changes: 22 additions & 3 deletions toys-rs/benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
use toys_rs::localpool::Pool;
use rand::random;

fn criterion_benchmark(c: &mut Criterion) {
let mut p:Pool<[u8;65536]>=unsafe{Pool::new()};
fn bench_pool(c: &mut Criterion) {
let mut p:Pool<[u64;16]>=Pool::new();
p.reserve(8192);
c.bench_function("pool one-shot", |b| b.iter(|| {
black_box(p.get());
}));
Expand All @@ -16,7 +17,25 @@ fn criterion_benchmark(c: &mut Criterion) {
}
}));
println!("{} in use, {} idling", v.len(), p.idle());
p.release(1024);
}

criterion_group!(benches, criterion_benchmark);
#[allow(deprecated)]
fn _bench_thinpool(c: &mut Criterion) {
use toys_rs::thinpool::Pool;
let mut p:Pool<u8>=unsafe{Pool::new()};
c.bench_function("thinpool one-shot", |b| b.iter(|| {
black_box(p.get());
}));
let mut v=Vec::new();
c.bench_function("thinpool random", |b| b.iter(|| {
match random::<bool>(){ // 2ns
true=>{v.push(p.get());}, // 2ns+4ns
false=>{black_box(v.pop());}
}
}));
println!("{} in use, {} idling", v.len(), p.idle());
}

criterion_group!(benches, bench_pool);
criterion_main!(benches);
2 changes: 2 additions & 0 deletions toys-rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Rust toy libraries
pub mod mem;
pub mod localpool;
#[deprecated="benchmark shows terrible performance"]
pub mod thinpool;
#[deprecated]
pub mod locallock;
66 changes: 52 additions & 14 deletions toys-rs/src/localpool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ Abandoned:
- variable `INIT_SIZE`: rust still has inferring bugs for generic const
*/

const INIT_SIZE:usize=8; // init size

struct RawPool<'a, T>{ // `'a`: lifetime for `newfn`
pool: Vec<*mut T>,
newfn: Box<dyn FnMut()->*mut T+'a>
Expand Down Expand Up @@ -66,22 +64,17 @@ impl<'a, T> Pool<'a, T>{
#[deprecated="use drop instead"]
pub fn put(&mut self, _: PoolBox<T>){}

fn with_new<New>(mut newfn: New)->Self
fn with_new<New>(newfn: New)->Self
where New:FnMut()->*mut T+'a{
let mut pool=Vec::with_capacity(INIT_SIZE);
for _ in 0..INIT_SIZE {
pool.push(newfn());
}
let pool=Vec::new();
Pool(Rc::new(UnsafeCell::new(RawPool{ pool, newfn: Box::new(newfn)})))
}

/// Constructs a new object Pool which provides empty `T` objeccts.
/// # Unsafe
/// Object are uninitialized.
pub unsafe fn new()->Self{
Self::with_new(||{
unsafe{mem::new()}
})
pub fn new()->Self{
Self::with_new(||unsafe{mem::new()})
}

/// Constructs a new object Pool which provides `T` objeccts
Expand Down Expand Up @@ -117,6 +110,37 @@ impl<'a, T> Pool<'a, T>{
}

pub fn idle(&self)->usize{self.inner().pool.len()}

/// Reserves idle objects for at least additional more items
/// to be got from the given Pool<T>.
pub fn reserve(&mut self, additional: usize){
let p=self.inner();
p.pool.resize_with(
p.pool.len()+additional,
&mut *p.newfn
)
}

/// release `n` idling objects
pub fn release(&mut self, n: usize){
let pool=&mut self.inner().pool;
unsafe{
if n>pool.len(){ // release all
for i in 0..pool.len(){
mem::delete(*pool.get_unchecked(i));
}
pool.set_len(0);
} else { // release n
for i in pool.len()-n..pool.len(){
mem::delete(*pool.get_unchecked(i));
}
pool.set_len(pool.len()-n);
}}
// shrink vector to half
if pool.capacity()>64 && pool.len()<pool.capacity()>>2{
pool.shrink_to(pool.len()<<1);
}
}
}

/// drop will only be called when Rc counter returns 0
Expand Down Expand Up @@ -178,7 +202,7 @@ mod tests {
let mut p = Pool::with_init(
|x|{*x=counter; counter+=1;}
);
assert_eq!(*p.get(), INIT_SIZE);
assert_eq!(*p.get(), 1);
drop(p);
}

Expand All @@ -195,17 +219,31 @@ mod tests {
use super::*;
let mut x=1;
let mut p=Pool::with_generator(||{let y=x; x+=1; y});
assert_eq!(*p.get(), INIT_SIZE);
assert_eq!(*p.get(), 1);
}

#[test]
fn test_clone(){
use super::*;
let p:Pool<i32>=Pool::with_init(|_|{});
let p:Pool<i32>=Pool::new();
let mut p1=p.clone();
drop(p1.get()); // make sure p1 not stripped
}

#[test]
fn test_reserve_release(){
use super::*;
use std::hint::black_box;
let mut p:Pool<i32>=Pool::new();
black_box(*p.get());
p.release(2); // does nothing
black_box(*p.get());
p.reserve(2);
assert_eq!(p.idle(),3);
p.release(2);
assert_eq!(p.idle(),1);
black_box(*p.get());
}

#[test]
fn test_tokio(){
Expand Down
2 changes: 1 addition & 1 deletion toys-rs/src/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ pub unsafe fn resize_arr<T>(ptr: *mut T, oldlen: usize, newlen: usize)->*mut T{

/// Returns a `*mut T` null pointer
#[inline(always)]
pub const fn nullptr<T>()->*mut T{0 as *mut T}
pub const fn nullptr<T>()->*mut T{0 as *mut T}
Loading

0 comments on commit 07afd8c

Please sign in to comment.