#![allow(dead_code)] extern crate syncpool; use std::collections::HashMap; use std::sync::mpsc; use std::thread; use std::time::{Duration, Instant}; use syncpool::prelude::*; const TRIAL_RUNS: usize = 64; const TEST_SIZE: usize = 128; const BUF_CAP: usize = 1024; const BUSY_PERIOD: u64 = 16; const DENOMINATOR: usize = 1; const ASYNC_MODE: bool = true; type TestStruct = Buffer; static mut POOL: Option> = None; //struct Buffer(Box<[u8; BUF_CAP]>); struct Buffer { id: usize, buf: [u8; BUF_CAP], } impl Buffer { fn len(&self) -> usize { self.buf.len() } } impl Default for Buffer { fn default() -> Self { let mut base = Buffer { id: 0, buf: [0u8; BUF_CAP], }; // let mut base = Buffer(Box::new([0u8; BUF_CAP])); base.buf[42] = 42; base } } #[derive(Default, Debug)] struct ComplexStruct { id: usize, name: String, body: Vec, flags: Vec, children: Vec, index: HashMap, rev_index: HashMap, } fn main() { pool_setup(); let async_mode = ASYNC_MODE; let trials = TRIAL_RUNS; let mut sum = 0; println!("Init len: {}", unsafe { POOL.as_ref().unwrap().len() }); for i in 0..trials { let res = if async_mode { let n = thread::spawn(|| run(true)); let p = thread::spawn(|| run(false)); let p_time = p.join().unwrap_or_default() as i128; let n_time = n.join().unwrap_or_default() as i128; n_time - p_time } else { let n_time = run(true) as i128; let p_time = run(false) as i128; n_time - p_time }; sum += res; println!(">>> Trial: {}; Advance: {} us <<<", i, res); // println!("Remainder len: {}", unsafe { POOL.as_ref().unwrap().len() }); } println!("Remainder len: {}", unsafe { POOL.as_ref().unwrap().len() }); println!( "\nAverage: {} ms\n", (sum as f64) / (trials as f64) / 1000f64 ); } fn pool_setup() { unsafe { let mut pool = SyncPool::with_size(128); // clean up the underlying buffer, this handle can also be used to shrink the underlying // buffer to save for space, though at a cost of extra overhead for doing that. pool.reset_handle(sanitizer); /* // Alternatively, use an anonymous function for the same purpose. Closure can't be used as // a handle, though. pool.reset_handle(|slice: &mut [u8; BUF_CAP]| { for i in 0..slice.len() { slice[i] = 0; } println!("Byte slice cleared..."); }); */ POOL.replace(pool); } } fn sanitizer(data: &mut TestStruct) { data.id = 21; } fn run(alloc: bool) -> u128 { let (tx, rx) = mpsc::sync_channel(32); let tx_clone = tx.clone(); let now = Instant::now(); let send_one = thread::spawn(move || { for i in 0..TEST_SIZE { if i % DENOMINATOR == 0 { thread::sleep(Duration::from_nanos(BUSY_PERIOD)); } let mut data = if alloc { Default::default() } else { unsafe { POOL.as_mut().unwrap().get() } }; assert!(data.id == 21 || data.id == 0, "Wrong id: {}", data.id); assert_ne!(data.id, 42); data.id = 42; /* assert_eq!(arr.len(), BUF_CAP); assert_eq!(arr.0[42], 42);*/ tx_clone.try_send(data).unwrap_or_default(); } // println!("Send one done..."); }); let send_two = thread::spawn(move || { for i in 0..TEST_SIZE { if i % DENOMINATOR == 0 { thread::sleep(Duration::from_nanos(BUSY_PERIOD)); } let mut data = if alloc { Default::default() } else { unsafe { POOL.as_mut().unwrap().get() } }; assert!(data.id == 21 || data.id == 0, "Wrong id: {}", data.id); assert_ne!(data.id, 42); data.id = 42; /* assert_eq!(arr.len(), BUF_CAP); assert_eq!(arr.0[42], 42);*/ tx.try_send(data).unwrap_or_default(); } // println!("Send two done..."); }); let recv_one = thread::spawn(move || { thread::sleep(Duration::from_micros(5)); while let Ok(arr) = rx.recv() { // assert_eq!(arr.len(), BUF_CAP); if !alloc { unsafe { POOL.as_mut().unwrap().put(arr); } } } // println!("Recv one done..."); }); for i in 0..TEST_SIZE { // sleep a bit to create some concurrent actions if i % DENOMINATOR == 1 { thread::sleep(Duration::from_nanos(BUSY_PERIOD)); } let mut data = if alloc { Default::default() } else { unsafe { POOL.as_mut().unwrap().get() } }; // assert!(data.id == 21 || data.id == 0, "Wrong id: {}", data.id); assert_ne!(data.id, 42); data.id = 42; /* assert_eq!(arr.len(), BUF_CAP); assert_eq!(arr.0[42], 42);*/ if !alloc { // when done using the object, make sure to put it back so the pool won't dry up unsafe { POOL.as_mut().unwrap().put(data) }; } } // println!("Main loop done..."); send_one.join().unwrap_or_default(); send_two.join().unwrap_or_default(); recv_one.join().unwrap_or_default(); now.elapsed().as_micros() }