Skip to content

Commit a5eff2f

Browse files
Merge pull request #570 from fortanix/nr-replace-stress-test-allocation
Replacing the allocation technique in memory allocation stress test
2 parents dda4629 + 1ffd520 commit a5eff2f

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

examples/mem-alloc-test/src/main.rs

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use rand::Rng;
2-
use num_cpus;
2+
use std::alloc::{alloc, dealloc, Layout};
3+
use std::ptr;
34
use std::sync::{Arc, Condvar, Mutex};
45
use std::thread;
5-
use std::time::{Instant};
6-
6+
use std::time::Instant;
77
#[derive(Debug, PartialEq)]
88
enum MemSize {
99
Large,
@@ -29,7 +29,6 @@ const TO_KB: usize = 1024;
2929
const TO_MB: usize = TO_KB * 1024;
3030
const TO_GB: usize = TO_MB * 1024;
3131

32-
3332
/* Set of configurable parameters. These will adjusted as necessary while
3433
* recording the performance numbers
3534
*/
@@ -54,15 +53,14 @@ const MAX_INDEX_CHECKS_PER_BUFFER: usize = 32;
5453

5554
fn calculate_and_print_stat(
5655
shared_mutex_clone: Arc<Mutex<Counters>>,
57-
tid: i32,
5856
memsize: &MemSize,
5957
avg_thread_latency: f64,
6058
) {
6159
/* TODO: Record some other statistical parameters like more detailed statistics
6260
* than just average, such as standard deviation, minimum and maximum time,
6361
* and p95/p99/p99.9 latency
6462
*/
65-
//println!("thread {} took {}\n", tid, avg_thread_latency);
63+
//println!("thread {} took {}\n", _tid, avg_thread_latency);
6664
let mut data = shared_mutex_clone.lock().unwrap();
6765
/* Please note this is an intermediate value. Once we get the sum of individual
6866
* averages of all the threads, then we will divide it by the frequency of
@@ -103,22 +101,22 @@ fn wakeup_all_child_threads(pair_clone: Arc<(Mutex<bool>, Condvar)>) {
103101
drop(started);
104102
}
105103

106-
fn traverse_buffer(buf: &mut Vec<i32>, scan_interval: usize) {
107-
let mut ptr = 0;
104+
fn traverse_buffer(buf: *mut u8, size: usize, _scan_interval: usize) {
108105
let num_indices_checks = get_random_num(1, MAX_INDEX_CHECKS_PER_BUFFER);
109-
for i in 1..=num_indices_checks {
106+
for _i in 1..=num_indices_checks {
110107
/* Check for random indices and number of such indices is num_indices_checks
111108
* Please note that depending on the number random number generator, we
112109
* can check for the same index multiple times. We could have checked
113110
* for all the indices but that would be too time consuming
114111
*/
115-
let index = get_random_num(0, buf.len() - 1);
116-
buf[index] = buf[index] * 2;
112+
let index = get_random_num(0, size - 1);
113+
unsafe {
114+
ptr::write(buf.offset(index as isize), 1);
115+
}
117116
}
118117
}
119118

120119
fn worker_thread(
121-
tid: i32,
122120
shared_mutex_clone: Arc<Mutex<Counters>>,
123121
memsize: MemSize,
124122
pair_clone: Arc<(Mutex<bool>, Condvar)>,
@@ -166,22 +164,30 @@ fn worker_thread(
166164
let start_time = Instant::now();
167165

168166
/* Create an array of x GB where x is a random number between 1 to 4 */
169-
let mut large_vector = Vec::with_capacity(size);
170-
large_vector.resize(size, 0);
167+
168+
// Create a layout based on the size and alignment
169+
let align = get_random_num(2, PAGE_SIZE).next_power_of_two();
170+
let layout = Layout::from_size_align(size, align).unwrap();
171+
172+
// Allocate memory using the global allocator
173+
let ptr = unsafe { alloc(layout) };
174+
assert!(!ptr.is_null());
171175

172176
/* Traverse and access the entire buffer so that pages are allocated */
173-
traverse_buffer(&mut large_vector, scan_interval);
177+
traverse_buffer(ptr, size, scan_interval);
174178

175179
/* deallocate */
176-
drop(large_vector);
180+
unsafe {
181+
dealloc(ptr, layout);
182+
}
177183

178184
/* calculate the metrics */
179185
let end_time = Instant::now();
180186
let duration = end_time.duration_since(start_time);
181187
tot_time_ns += duration.as_nanos();
182188

183189
count = count + 1;
184-
if (count >= limit) {
190+
if count >= limit {
185191
break;
186192
}
187193
}
@@ -193,7 +199,7 @@ fn worker_thread(
193199
let avg_thread_latency = tot_time_ns as f64 / count as f64;
194200

195201
let shared_mutex_clone_2 = Arc::clone(&shared_mutex_clone);
196-
calculate_and_print_stat(shared_mutex_clone_2, tid, &memsize, avg_thread_latency);
202+
calculate_and_print_stat(shared_mutex_clone_2, &memsize, avg_thread_latency);
197203
}
198204

199205
fn spawn_threads(thread_count: i32) {
@@ -211,13 +217,12 @@ fn spawn_threads(thread_count: i32) {
211217
let shared_mutex_clone = Arc::clone(&shared_variable);
212218
// Spawn a thread that waits until the condition is met
213219
let pair_clone = Arc::clone(&pair);
214-
let mut memtype;
220+
let memtype;
215221

216222
match i % 2 {
217223
0 => {
218224
memtype = MemSize::Small;
219225
num_small_threads += 1;
220-
221226
}
222227
1 => {
223228
memtype = MemSize::Medium;
@@ -231,7 +236,7 @@ fn spawn_threads(thread_count: i32) {
231236
};
232237

233238
let handle = thread::spawn(move || {
234-
worker_thread(i, shared_mutex_clone, memtype, pair_clone);
239+
worker_thread(shared_mutex_clone, memtype, pair_clone);
235240
});
236241
handles.push(handle);
237242
}
@@ -246,17 +251,20 @@ fn spawn_threads(thread_count: i32) {
246251

247252
/* Calculate final means */
248253
let mut data = shared_variable.lock().unwrap();
249-
if (num_large_threads != 0) {
254+
if num_large_threads != 0 {
250255
data.avg_duration_large_thread = data.avg_duration_large_thread / num_large_threads as f64;
251256
}
252257
data.avg_duration_medium_thread = data.avg_duration_medium_thread / num_medium_threads as f64;
253258
data.avg_duration_small_thread = data.avg_duration_small_thread / num_small_threads as f64;
254259

255-
data.global_average = (data.avg_duration_small_thread * num_small_threads as f64 * LIMIT_SMALL_THREAD as f64
260+
data.global_average = (data.avg_duration_small_thread
261+
* num_small_threads as f64
262+
* LIMIT_SMALL_THREAD as f64
256263
+ data.avg_duration_medium_thread * num_medium_threads as f64 * LIMIT_MEDIUM_THREAD as f64
257264
+ data.avg_duration_large_thread * num_large_threads as f64 * LIMIT_LARGE_THREAD as f64)
258-
/ (num_large_threads * LIMIT_LARGE_THREAD +
259-
num_medium_threads * LIMIT_MEDIUM_THREAD + num_small_threads * LIMIT_SMALL_THREAD) as f64;
265+
/ (num_large_threads * LIMIT_LARGE_THREAD
266+
+ num_medium_threads * LIMIT_MEDIUM_THREAD
267+
+ num_small_threads * LIMIT_SMALL_THREAD) as f64;
260268
println!(
261269
"{},{},{},{},{}",
262270
thread_count,
@@ -280,9 +288,9 @@ fn get_num_processors() -> usize {
280288
*/
281289
fn start_tests() {
282290
println!("NUM_THREADS,LATENCY_SMALL_THREADS,LATENCY_MEDIUM_THREADS,LATENCY_LARGE_THREADS,GLOBAL_AVERAGE");
283-
let mut num_processors = get_num_processors();
291+
let num_processors = get_num_processors();
284292
let mut num_threads = num_processors * 2;
285-
while (num_threads >= 3) {
293+
while num_threads >= 3 {
286294
spawn_threads(num_threads as i32);
287295
num_threads = num_threads >> 1;
288296
}

examples/mem-correctness-test/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ sha2 = "0.10"
1414
[package.metadata.fortanix-sgx]
1515
# heap size (in bytes), the default heap size is 0x2000000.
1616
heap-size=0x20000000
17-
debug=false
17+
debug=false

0 commit comments

Comments
 (0)