complex_bench/
complex_bench.rs

1#![allow(dead_code)]
2
3extern crate syncpool;
4
5use std::collections::HashMap;
6use std::sync::mpsc;
7use std::thread;
8use std::time::{Duration, Instant};
9use syncpool::prelude::*;
10
11const TRIAL_RUNS: usize = 64;
12const TEST_SIZE: usize = 128;
13const BUF_CAP: usize = 1024;
14const BUSY_PERIOD: u64 = 16;
15const DENOMINATOR: usize = 1;
16const ASYNC_MODE: bool = true;
17
18type TestStruct = Buffer;
19static mut POOL: Option<SyncPool<TestStruct>> = None;
20
21//struct Buffer(Box<[u8; BUF_CAP]>);
22struct Buffer {
23    id: usize,
24    buf: [u8; BUF_CAP],
25}
26
27impl Buffer {
28    fn len(&self) -> usize {
29        self.buf.len()
30    }
31}
32
33impl Default for Buffer {
34    fn default() -> Self {
35        let mut base = Buffer {
36            id: 0,
37            buf: [0u8; BUF_CAP],
38        };
39
40        //        let mut base = Buffer(Box::new([0u8; BUF_CAP]));
41
42        base.buf[42] = 42;
43        base
44    }
45}
46
47#[derive(Default, Debug)]
48struct ComplexStruct {
49    id: usize,
50    name: String,
51    body: Vec<String>,
52    flags: Vec<usize>,
53    children: Vec<usize>,
54    index: HashMap<usize, String>,
55    rev_index: HashMap<String, usize>,
56}
57
58fn main() {
59    pool_setup();
60
61    let async_mode = ASYNC_MODE;
62    let trials = TRIAL_RUNS;
63    let mut sum = 0;
64
65    println!("Init len: {}", unsafe { POOL.as_ref().unwrap().len() });
66
67    for i in 0..trials {
68        let res = if async_mode {
69            let n = thread::spawn(|| run(true));
70            let p = thread::spawn(|| run(false));
71
72            let p_time = p.join().unwrap_or_default() as i128;
73            let n_time = n.join().unwrap_or_default() as i128;
74
75            n_time - p_time
76        } else {
77            let n_time = run(true) as i128;
78            let p_time = run(false) as i128;
79
80            n_time - p_time
81        };
82
83        sum += res;
84
85        println!(">>> Trial: {}; Advance: {} us <<<", i, res);
86        //        println!("Remainder len: {}", unsafe { POOL.as_ref().unwrap().len() });
87    }
88
89    println!("Remainder len: {}", unsafe { POOL.as_ref().unwrap().len() });
90
91    println!(
92        "\nAverage: {} ms\n",
93        (sum as f64) / (trials as f64) / 1000f64
94    );
95}
96
97fn pool_setup() {
98    unsafe {
99        let mut pool = SyncPool::with_size(128);
100
101        // clean up the underlying buffer, this handle can also be used to shrink the underlying
102        // buffer to save for space, though at a cost of extra overhead for doing that.
103        pool.reset_handle(sanitizer);
104
105        /*
106        // Alternatively, use an anonymous function for the same purpose. Closure can't be used as
107        // a handle, though.
108        pool.reset_handle(|slice: &mut [u8; BUF_CAP]| {
109            for i in 0..slice.len() {
110                slice[i] = 0;
111            }
112
113            println!("Byte slice cleared...");
114        });
115        */
116
117        POOL.replace(pool);
118    }
119}
120
121fn sanitizer(data: &mut TestStruct) {
122    data.id = 21;
123}
124
125fn run(alloc: bool) -> u128 {
126    let (tx, rx) = mpsc::sync_channel(32);
127    let tx_clone = tx.clone();
128
129    let now = Instant::now();
130
131    let send_one = thread::spawn(move || {
132        for i in 0..TEST_SIZE {
133            if i % DENOMINATOR == 0 {
134                thread::sleep(Duration::from_nanos(BUSY_PERIOD));
135            }
136
137            let mut data = if alloc {
138                Default::default()
139            } else {
140                unsafe { POOL.as_mut().unwrap().get() }
141            };
142
143            assert!(data.id == 21 || data.id == 0, "Wrong id: {}", data.id);
144            assert_ne!(data.id, 42);
145            data.id = 42;
146
147            /*            assert_eq!(arr.len(), BUF_CAP);
148            assert_eq!(arr.0[42], 42);*/
149
150            tx_clone.try_send(data).unwrap_or_default();
151        }
152
153        //        println!("Send one done...");
154    });
155
156    let send_two = thread::spawn(move || {
157        for i in 0..TEST_SIZE {
158            if i % DENOMINATOR == 0 {
159                thread::sleep(Duration::from_nanos(BUSY_PERIOD));
160            }
161
162            let mut data = if alloc {
163                Default::default()
164            } else {
165                unsafe { POOL.as_mut().unwrap().get() }
166            };
167
168            assert!(data.id == 21 || data.id == 0, "Wrong id: {}", data.id);
169            assert_ne!(data.id, 42);
170            data.id = 42;
171
172            /*            assert_eq!(arr.len(), BUF_CAP);
173            assert_eq!(arr.0[42], 42);*/
174
175            tx.try_send(data).unwrap_or_default();
176        }
177
178        //        println!("Send two done...");
179    });
180
181    let recv_one = thread::spawn(move || {
182        thread::sleep(Duration::from_micros(5));
183
184        while let Ok(arr) = rx.recv() {
185            //            assert_eq!(arr.len(), BUF_CAP);
186
187            if !alloc {
188                unsafe {
189                    POOL.as_mut().unwrap().put(arr);
190                }
191            }
192        }
193
194        //        println!("Recv one done...");
195    });
196
197    for i in 0..TEST_SIZE {
198        // sleep a bit to create some concurrent actions
199        if i % DENOMINATOR == 1 {
200            thread::sleep(Duration::from_nanos(BUSY_PERIOD));
201        }
202
203        let mut data = if alloc {
204            Default::default()
205        } else {
206            unsafe { POOL.as_mut().unwrap().get() }
207        };
208
209        //        assert!(data.id == 21 || data.id == 0, "Wrong id: {}", data.id);
210        assert_ne!(data.id, 42);
211        data.id = 42;
212
213        /*        assert_eq!(arr.len(), BUF_CAP);
214        assert_eq!(arr.0[42], 42);*/
215
216        if !alloc {
217            // when done using the object, make sure to put it back so the pool won't dry up
218            unsafe { POOL.as_mut().unwrap().put(data) };
219        }
220    }
221
222    //    println!("Main loop done...");
223
224    send_one.join().unwrap_or_default();
225    send_two.join().unwrap_or_default();
226    recv_one.join().unwrap_or_default();
227
228    now.elapsed().as_micros()
229}