diff --git a/examples/mem-alloc-test/.gitignore b/examples/mem-alloc-test/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/examples/mem-alloc-test/.gitignore @@ -0,0 +1 @@ +/target diff --git a/examples/mem-alloc-test/Cargo.toml b/examples/mem-alloc-test/Cargo.toml new file mode 100644 index 00000000..63340c62 --- /dev/null +++ b/examples/mem-alloc-test/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "mem-alloc-test" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.4" \ No newline at end of file diff --git a/examples/mem-alloc-test/src/main.rs b/examples/mem-alloc-test/src/main.rs new file mode 100644 index 00000000..c4b2cffe --- /dev/null +++ b/examples/mem-alloc-test/src/main.rs @@ -0,0 +1,152 @@ +use core::arch::global_asm; +use std::{thread}; +use std::time::{Instant, Duration}; +use rand::Rng; +use std::sync::{Mutex, Arc}; + + +enum SizeType { + LARGE_MEM, + MEDIUM_MEM, + LOW_MEM, +} + +fn calculateAndPrintStat(shared_mutex_clone: Arc>, + shared_mutex_dur_clone: Arc>, + duration: Duration, tid: i32, memtypestr: &str) { + + /* This function continuosly prints the average execution time of the worker + * thread which includes time to allocate a buffer + time to traverse it + + * time to free it. + * TODO: Currently the average is taken over all threads (large, medium and + * small). I will a separate average timings for small, medium and large + * buffer threads + */ + + let duration_ms = duration.as_nanos(); + let mut data = shared_mutex_clone.lock().unwrap(); + *data += 1; + let mut data_d = shared_mutex_dur_clone.lock().unwrap(); + *data_d += duration_ms; + let avg_exec_time = *data_d as f64 / *data as f64; + + if ((*data % 10001 == 0 && memtypestr == "LOW") || + (*data % 1001 == 0 && memtypestr == "MEDIUM") || + (*data % 12 == 0 && memtypestr == "LARGE")) { + println!("Thread {} ({})records count {} avg execution time {}", tid, + memtypestr, *data, avg_exec_time); + } +} + + +fn Get_Random_Num(start: usize, end: usize) -> usize { + let mut rng = rand::thread_rng(); + let random_number: usize = rng.gen_range(start..=end); + return random_number; +} + +fn worker_thread(tid: i32, shared_mutex_clone: Arc>, + shared_mutex_dur_clone: Arc>, memtype: SizeType) { + loop { + let mut page_size = 4096; + let to_kb = 1024; + let to_mb = to_kb * 1024; + let to_gb = to_mb * 1024; + + let mut ran_num = 0; + let mut size = 0; + let mut scan_interval = page_size; + let memtypestr; + + /* Create a random size depending on the memory type */ + match memtype { + SizeType::LARGE_MEM => { + /* buffer size will be from 1GB to 4GB */ + scan_interval = page_size; + ran_num = Get_Random_Num(1 , 4); + size = to_gb * ran_num; + memtypestr = String::from("LARGE"); + } + SizeType::MEDIUM_MEM => { + /* buffer size will be from 8MB to 128 */ + scan_interval = 1 * to_mb; + ran_num = Get_Random_Num(1 , 128); + size = to_mb * ran_num; + memtypestr = String::from("MEDIUM"); + + } + SizeType::LOW_MEM => { + /* buffer size will be from 1KB to 512KB */ + scan_interval = 1 * to_kb; + ran_num = Get_Random_Num(1 , 512); + size = to_kb * ran_num; + memtypestr = String::from("LOW"); + } + } + + + let start_time = Instant::now(); + + /* Create an array of x GB where x is a random number between 1 to 4 */ + let mut large_vector = Vec::with_capacity(size); + large_vector.resize(size, 0); + + /* Traverse and access the entire buffer so that pages are allocated */ + let mut ptr = 0; + + loop { + if (ptr >= size) { + break; + } + large_vector[ptr] = (large_vector[ptr] + 1) * 2; + ptr = ptr + scan_interval; + } + /* deallocate */ + drop(large_vector); + + /* calculate the metrics */ + let end_time = Instant::now(); + let duration = end_time.duration_since(start_time); + + let shared_mutex_clone_2 = Arc::clone(&shared_mutex_clone); + let shared_mutex_dur_clone_2 = Arc::clone(&shared_mutex_dur_clone); + calculateAndPrintStat(shared_mutex_clone_2, shared_mutex_dur_clone_2, + duration, tid, &memtypestr); + + } +} + +fn spawn_threads() { + let thread_count = 64; + let mut handles = vec![]; + let shared_variable = Arc::new(Mutex::new(0)); + let shared_variable_duration = Arc::new(Mutex::new(0_u128)); + + for i in 0..thread_count { + let shared_mutex_clone = Arc::clone(&shared_variable); + let shared_mutex_dur_clone = Arc::clone(&shared_variable_duration); + + let mut memtype = SizeType::LARGE_MEM; + if (i % 3 == 0) { + memtype = SizeType::LARGE_MEM; + } else if (i % 3 == 1) { + memtype = SizeType::MEDIUM_MEM; + } else { + memtype = SizeType::LOW_MEM; + } + + let handle = thread::spawn(move || { + worker_thread(i, shared_mutex_clone, shared_mutex_dur_clone, memtype); + }); + handles.push(handle); + } + + // Wait for all threads to finish + for handle in handles { + handle.join().unwrap(); + } +} + +fn main() { + spawn_threads(); +}