Skip to content

Commit

Permalink
Added a stress test for memory allocation (snmalloc)
Browse files Browse the repository at this point in the history
  • Loading branch information
NirjharRoyiitk committed Mar 15, 2024
1 parent e3f87a0 commit c776874
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/mem-alloc-test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
9 changes: 9 additions & 0 deletions examples/mem-alloc-test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
152 changes: 152 additions & 0 deletions examples/mem-alloc-test/src/main.rs
Original file line number Diff line number Diff line change
@@ -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<Mutex<i32>>,
shared_mutex_dur_clone: Arc<Mutex<u128>>,
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<Mutex<i32>>,
shared_mutex_dur_clone: Arc<Mutex<u128>>, 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();
}

0 comments on commit c776874

Please sign in to comment.