1
1
const USAGE : & ' static str = "
2
2
Usage: life bench [--size N] [--gens N]
3
+ life play [--size N] [--gens N] [--fps N]
3
4
life --help
4
5
Conway's Game of Life.
5
6
6
7
Commands:
7
8
bench Run the benchmark in different modes and print the timings.
9
+ play Run with a max frame rate and monitor CPU resources.
8
10
Options:
9
11
--size N Size of the game board (N x N) [default: 200]
10
12
--gens N Simulate N generations [default: 100]
13
+ --fps N Maximum frame rate [default: 60]
11
14
-h, --help Show this message.
12
15
" ;
13
16
@@ -17,6 +20,7 @@ use rand::distributions::Standard;
17
20
use std:: iter:: repeat;
18
21
use std:: num:: Wrapping ;
19
22
use std:: sync:: Arc ;
23
+ use std:: thread;
20
24
use time;
21
25
22
26
use docopt:: Docopt ;
@@ -25,12 +29,15 @@ use rayon::iter::ParallelBridge;
25
29
26
30
#[ cfg( test) ]
27
31
mod bench;
32
+ mod cpu_time;
28
33
29
34
#[ derive( Deserialize ) ]
30
35
pub struct Args {
31
36
cmd_bench : bool ,
37
+ cmd_play : bool ,
32
38
flag_size : usize ,
33
39
flag_gens : usize ,
40
+ flag_fps : usize ,
34
41
}
35
42
36
43
#[ derive( PartialEq , Eq , Clone , Debug ) ]
@@ -161,6 +168,44 @@ fn par_bridge_generations(board: Board, gens: usize) {
161
168
for _ in 0 ..gens { brd = brd. par_bridge_next_generation ( ) ; }
162
169
}
163
170
171
+ fn delay ( last_start : u64 , min_interval_ns : u64 ) -> u64 {
172
+ let mut current_time = time:: precise_time_ns ( ) ;
173
+ let elapsed = current_time - last_start;
174
+ if elapsed < min_interval_ns {
175
+ let delay = min_interval_ns - elapsed;
176
+ thread:: sleep ( :: std:: time:: Duration :: from_nanos ( delay) ) ;
177
+ current_time += delay;
178
+ }
179
+ current_time
180
+ }
181
+
182
+ fn generations_limited ( board : Board , gens : usize , min_interval_ns : u64 ) {
183
+ let mut brd = board;
184
+ let mut time = time:: precise_time_ns ( ) ;
185
+ for _ in 0 ..gens {
186
+ brd = brd. next_generation ( ) ;
187
+ time = delay ( time, min_interval_ns) ;
188
+ }
189
+ }
190
+
191
+ fn parallel_generations_limited ( board : Board , gens : usize , min_interval_ns : u64 ) {
192
+ let mut brd = board;
193
+ let mut time = time:: precise_time_ns ( ) ;
194
+ for _ in 0 ..gens {
195
+ brd = brd. parallel_next_generation ( ) ;
196
+ time = delay ( time, min_interval_ns) ;
197
+ }
198
+ }
199
+
200
+ fn par_bridge_generations_limited ( board : Board , gens : usize , min_interval_ns : u64 ) {
201
+ let mut brd = board;
202
+ let mut time = time:: precise_time_ns ( ) ;
203
+ for _ in 0 ..gens {
204
+ brd = brd. par_bridge_next_generation ( ) ;
205
+ time = delay ( time, min_interval_ns) ;
206
+ }
207
+ }
208
+
164
209
fn measure ( f : fn ( Board , usize ) -> ( ) , args : & Args ) -> u64 {
165
210
let ( n, gens) = ( args. flag_size , args. flag_gens ) ;
166
211
let brd = Board :: new ( n, n) . random ( ) ;
@@ -171,6 +216,31 @@ fn measure(f: fn(Board, usize) -> (), args: &Args) -> u64 {
171
216
time:: precise_time_ns ( ) - start
172
217
}
173
218
219
+ struct CpuResult {
220
+ actual_fps : f64 ,
221
+ cpu_usage_percent : Option < f64 > ,
222
+ }
223
+
224
+ fn measure_cpu ( f : fn ( Board , usize , u64 ) -> ( ) , args : & Args ) -> CpuResult {
225
+ let ( n, gens, rate) = ( args. flag_size , args. flag_gens , args. flag_fps ) ;
226
+ let interval = 1_000_000_000 / rate as u64 ;
227
+ let brd = Board :: new ( n, n) . random ( ) ;
228
+ let start = time:: precise_time_ns ( ) ;
229
+ let cpu_start = cpu_time:: get_cpu_time ( ) ;
230
+
231
+ f ( brd, gens, interval) ;
232
+
233
+ let cpu_stop = cpu_time:: get_cpu_time ( ) ;
234
+ let duration = time:: precise_time_ns ( ) - start;
235
+
236
+ CpuResult {
237
+ actual_fps : ( 1_000_000_000.0 * gens as f64 ) / duration as f64 ,
238
+ cpu_usage_percent : cpu_time:: get_cpu_duration ( cpu_start, cpu_stop)
239
+ . and_then ( |cpu| cpu. num_nanoseconds ( ) )
240
+ . and_then ( |cpu| Some ( 100.0 * cpu as f64 / duration as f64 ) ) ,
241
+ }
242
+ }
243
+
174
244
pub fn main ( args : & [ String ] ) {
175
245
let args: Args =
176
246
Docopt :: new ( USAGE )
@@ -183,10 +253,30 @@ pub fn main(args: &[String]) {
183
253
184
254
let parallel = measure ( parallel_generations, & args) ;
185
255
println ! ( "parallel: {:10} ns -> {:.2}x speedup" , parallel,
186
- serial as f64 / parallel as f64 ) ;
256
+ serial as f64 / parallel as f64 ) ;
187
257
188
258
let par_bridge = measure ( par_bridge_generations, & args) ;
189
259
println ! ( "par_bridge: {:10} ns -> {:.2}x speedup" , par_bridge,
190
- serial as f64 / par_bridge as f64 ) ;
260
+ serial as f64 / par_bridge as f64 ) ;
261
+ }
262
+
263
+ if args. cmd_play {
264
+ let serial = measure_cpu ( generations_limited, & args) ;
265
+ println ! ( " serial: {:.2} fps" , serial. actual_fps) ;
266
+ if let Some ( cpu_usage) = serial. cpu_usage_percent {
267
+ println ! ( " cpu usage: {:.1}%" , cpu_usage) ;
268
+ }
269
+
270
+ let parallel = measure_cpu ( parallel_generations_limited, & args) ;
271
+ println ! ( "parallel: {:.2} fps" , parallel. actual_fps) ;
272
+ if let Some ( cpu_usage) = parallel. cpu_usage_percent {
273
+ println ! ( " cpu usage: {:.1}%" , cpu_usage) ;
274
+ }
275
+
276
+ let par_bridge = measure_cpu ( par_bridge_generations_limited, & args) ;
277
+ println ! ( "par_bridge: {:.2} fps" , par_bridge. actual_fps) ;
278
+ if let Some ( cpu_usage) = par_bridge. cpu_usage_percent {
279
+ println ! ( " cpu usage: {:.1}%" , cpu_usage) ;
280
+ }
191
281
}
192
282
}
0 commit comments