1
1
use rand:: Rng ;
2
- use num_cpus;
2
+ use std:: alloc:: { alloc, dealloc, Layout } ;
3
+ use std:: ptr;
3
4
use std:: sync:: { Arc , Condvar , Mutex } ;
4
5
use std:: thread;
5
- use std:: time:: { Instant } ;
6
-
6
+ use std:: time:: Instant ;
7
7
#[ derive( Debug , PartialEq ) ]
8
8
enum MemSize {
9
9
Large ,
@@ -29,7 +29,6 @@ const TO_KB: usize = 1024;
29
29
const TO_MB : usize = TO_KB * 1024 ;
30
30
const TO_GB : usize = TO_MB * 1024 ;
31
31
32
-
33
32
/* Set of configurable parameters. These will adjusted as necessary while
34
33
* recording the performance numbers
35
34
*/
@@ -54,15 +53,14 @@ const MAX_INDEX_CHECKS_PER_BUFFER: usize = 32;
54
53
55
54
fn calculate_and_print_stat (
56
55
shared_mutex_clone : Arc < Mutex < Counters > > ,
57
- tid : i32 ,
58
56
memsize : & MemSize ,
59
57
avg_thread_latency : f64 ,
60
58
) {
61
59
/* TODO: Record some other statistical parameters like more detailed statistics
62
60
* than just average, such as standard deviation, minimum and maximum time,
63
61
* and p95/p99/p99.9 latency
64
62
*/
65
- //println!("thread {} took {}\n", tid , avg_thread_latency);
63
+ //println!("thread {} took {}\n", _tid , avg_thread_latency);
66
64
let mut data = shared_mutex_clone. lock ( ) . unwrap ( ) ;
67
65
/* Please note this is an intermediate value. Once we get the sum of individual
68
66
* 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)>) {
103
101
drop ( started) ;
104
102
}
105
103
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 ) {
108
105
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 {
110
107
/* Check for random indices and number of such indices is num_indices_checks
111
108
* Please note that depending on the number random number generator, we
112
109
* can check for the same index multiple times. We could have checked
113
110
* for all the indices but that would be too time consuming
114
111
*/
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
+ }
117
116
}
118
117
}
119
118
120
119
fn worker_thread (
121
- tid : i32 ,
122
120
shared_mutex_clone : Arc < Mutex < Counters > > ,
123
121
memsize : MemSize ,
124
122
pair_clone : Arc < ( Mutex < bool > , Condvar ) > ,
@@ -166,22 +164,30 @@ fn worker_thread(
166
164
let start_time = Instant :: now ( ) ;
167
165
168
166
/* 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( ) ) ;
171
175
172
176
/* 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) ;
174
178
175
179
/* deallocate */
176
- drop ( large_vector) ;
180
+ unsafe {
181
+ dealloc ( ptr, layout) ;
182
+ }
177
183
178
184
/* calculate the metrics */
179
185
let end_time = Instant :: now ( ) ;
180
186
let duration = end_time. duration_since ( start_time) ;
181
187
tot_time_ns += duration. as_nanos ( ) ;
182
188
183
189
count = count + 1 ;
184
- if ( count >= limit) {
190
+ if count >= limit {
185
191
break ;
186
192
}
187
193
}
@@ -193,7 +199,7 @@ fn worker_thread(
193
199
let avg_thread_latency = tot_time_ns as f64 / count as f64 ;
194
200
195
201
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) ;
197
203
}
198
204
199
205
fn spawn_threads ( thread_count : i32 ) {
@@ -211,13 +217,12 @@ fn spawn_threads(thread_count: i32) {
211
217
let shared_mutex_clone = Arc :: clone ( & shared_variable) ;
212
218
// Spawn a thread that waits until the condition is met
213
219
let pair_clone = Arc :: clone ( & pair) ;
214
- let mut memtype;
220
+ let memtype;
215
221
216
222
match i % 2 {
217
223
0 => {
218
224
memtype = MemSize :: Small ;
219
225
num_small_threads += 1 ;
220
-
221
226
}
222
227
1 => {
223
228
memtype = MemSize :: Medium ;
@@ -231,7 +236,7 @@ fn spawn_threads(thread_count: i32) {
231
236
} ;
232
237
233
238
let handle = thread:: spawn ( move || {
234
- worker_thread ( i , shared_mutex_clone, memtype, pair_clone) ;
239
+ worker_thread ( shared_mutex_clone, memtype, pair_clone) ;
235
240
} ) ;
236
241
handles. push ( handle) ;
237
242
}
@@ -246,17 +251,20 @@ fn spawn_threads(thread_count: i32) {
246
251
247
252
/* Calculate final means */
248
253
let mut data = shared_variable. lock ( ) . unwrap ( ) ;
249
- if ( num_large_threads != 0 ) {
254
+ if num_large_threads != 0 {
250
255
data. avg_duration_large_thread = data. avg_duration_large_thread / num_large_threads as f64 ;
251
256
}
252
257
data. avg_duration_medium_thread = data. avg_duration_medium_thread / num_medium_threads as f64 ;
253
258
data. avg_duration_small_thread = data. avg_duration_small_thread / num_small_threads as f64 ;
254
259
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
256
263
+ data. avg_duration_medium_thread * num_medium_threads as f64 * LIMIT_MEDIUM_THREAD as f64
257
264
+ 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 ;
260
268
println ! (
261
269
"{},{},{},{},{}" ,
262
270
thread_count,
@@ -280,9 +288,9 @@ fn get_num_processors() -> usize {
280
288
*/
281
289
fn start_tests ( ) {
282
290
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 ( ) ;
284
292
let mut num_threads = num_processors * 2 ;
285
- while ( num_threads >= 3 ) {
293
+ while num_threads >= 3 {
286
294
spawn_threads ( num_threads as i32 ) ;
287
295
num_threads = num_threads >> 1 ;
288
296
}
0 commit comments