-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a stress test for memory allocation (snmalloc)
- Loading branch information
1 parent
e3f87a0
commit c776874
Showing
3 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |