@@ -8,6 +8,8 @@ use merge::Merge;
88use once_cell:: sync:: Lazy ;
99use schemars:: { schema_for, JsonSchema } ;
1010use serde:: { Deserialize , Serialize } ;
11+ use std:: convert:: TryInto ;
12+ use std:: num:: NonZeroU32 ;
1113
1214use super :: simulation_time:: { SIMTIME_ONE_NANOSECOND , SIMTIME_ONE_SECOND } ;
1315use super :: units:: { self , Unit } ;
@@ -133,11 +135,13 @@ pub struct GeneralOptions {
133135 #[ serde( default = "default_some_1" ) ]
134136 seed : Option < u32 > ,
135137
136- /// Run concurrently with N worker threads
137- #[ clap( long, short = 'w' , value_name = "N" ) ]
138- #[ clap( about = GENERAL_HELP . get( "workers" ) . unwrap( ) ) ]
139- #[ serde( default = "default_some_0" ) ]
140- workers : Option < u32 > ,
138+ /// How many parallel threads to use to run the simulation. Optimal
139+ /// performance is usually obtained with `nproc`, or sometimes `nproc/2`
140+ /// with hyperthreading.
141+ #[ clap( long, short = 'p' , value_name = "cores" ) ]
142+ #[ clap( about = GENERAL_HELP . get( "parallelism" ) . unwrap( ) ) ]
143+ #[ serde( default = "default_some_nz_1" ) ]
144+ parallelism : Option < NonZeroU32 > ,
141145
142146 #[ clap( long, value_name = "seconds" ) ]
143147 #[ clap( about = GENERAL_HELP . get( "bootstrap_end_time" ) . unwrap( ) ) ]
@@ -221,11 +225,6 @@ pub struct ExperimentalOptions {
221225 #[ clap( about = EXP_HELP . get( "preload_spin_max" ) . unwrap( ) ) ]
222226 preload_spin_max : Option < i32 > ,
223227
224- /// Maximum number of workers to allow to run at once
225- #[ clap( long, value_name = "workers" ) ]
226- #[ clap( about = EXP_HELP . get( "max_concurrency" ) . unwrap( ) ) ]
227- max_concurrency : Option < i32 > ,
228-
229228 /// Use the MemoryManager. It can be useful to disable for debugging, but will hurt performance in
230229 /// most cases
231230 #[ clap( long, value_name = "bool" ) ]
@@ -286,6 +285,16 @@ pub struct ExperimentalOptions {
286285 #[ clap( long, value_name = "mode" ) ]
287286 #[ clap( about = EXP_HELP . get( "interface_qdisc" ) . unwrap( ) ) ]
288287 interface_qdisc : Option < QDiscMode > ,
288+
289+ /// Create N worker threads. Note though, that `--parallelism` of them will
290+ /// be allowed to run simultaneously. If unset, will create a thread for
291+ /// each simulated Host. This is to work around limitations in ptrace, and
292+ /// may change in the future. "0" is a valid value, and will cause the
293+ /// simulation to be run directly on the main Shadow thread, but this
294+ /// functionality may be removed in the future.
295+ #[ clap( long, value_name = "N" ) ]
296+ #[ clap( about = EXP_HELP . get( "worker_threads" ) . unwrap( ) ) ]
297+ worker_threads : Option < u32 > ,
289298}
290299
291300impl ExperimentalOptions {
@@ -305,19 +314,19 @@ impl Default for ExperimentalOptions {
305314 use_syscall_counters : Some ( false ) ,
306315 use_object_counters : Some ( true ) ,
307316 preload_spin_max : Some ( 0 ) ,
308- max_concurrency : None ,
309317 use_memory_manager : Some ( true ) ,
310318 use_shim_syscall_handler : Some ( true ) ,
311319 use_cpu_pinning : Some ( true ) ,
312320 interpose_method : Some ( InterposeMethod :: Ptrace ) ,
313321 runahead : None ,
314- scheduler_policy : Some ( SchedulerPolicy :: Steal ) ,
322+ scheduler_policy : Some ( SchedulerPolicy :: Host ) ,
315323 socket_send_buffer : Some ( units:: Bytes :: new ( 131_072 , units:: SiPrefixUpper :: Base ) ) ,
316324 socket_send_autotune : Some ( true ) ,
317325 socket_recv_buffer : Some ( units:: Bytes :: new ( 174_760 , units:: SiPrefixUpper :: Base ) ) ,
318326 socket_recv_autotune : Some ( true ) ,
319327 interface_buffer : Some ( units:: Bytes :: new ( 1_024_000 , units:: SiPrefixUpper :: Base ) ) ,
320328 interface_qdisc : Some ( QDiscMode :: Fifo ) ,
329+ worker_threads : None ,
321330 }
322331 }
323332}
@@ -640,16 +649,16 @@ fn default_some_time_0() -> Option<units::Time<units::TimePrefixUpper>> {
640649 Some ( units:: Time :: new ( 0 , units:: TimePrefixUpper :: Sec ) )
641650}
642651
643- /// Helper function for serde default `Some(0)` values.
644- fn default_some_0 ( ) -> Option < u32 > {
645- Some ( 0 )
646- }
647-
648652/// Helper function for serde default `Some(1)` values.
649653fn default_some_1 ( ) -> Option < u32 > {
650654 Some ( 1 )
651655}
652656
657+ /// Helper function for serde default `Some(1)` values.
658+ fn default_some_nz_1 ( ) -> Option < NonZeroU32 > {
659+ Some ( std:: num:: NonZeroU32 :: new ( 1 ) . unwrap ( ) )
660+ }
661+
653662/// Helper function for serde default `Some(0)` values.
654663fn default_some_time_1 ( ) -> Option < units:: Time < units:: TimePrefixUpper > > {
655664 Some ( units:: Time :: new ( 1 , units:: TimePrefixUpper :: Sec ) )
@@ -1106,13 +1115,10 @@ mod export {
11061115 }
11071116
11081117 #[ no_mangle]
1109- pub extern "C" fn config_getMaxConcurrency ( config : * const ConfigOptions ) -> i32 {
1118+ pub extern "C" fn config_getParallelism ( config : * const ConfigOptions ) -> NonZeroU32 {
11101119 assert ! ( !config. is_null( ) ) ;
11111120 let config = unsafe { & * config } ;
1112- match config. experimental . max_concurrency {
1113- Some ( x) => x,
1114- None => -1 ,
1115- }
1121+ config. general . parallelism . unwrap ( )
11161122 }
11171123
11181124 #[ no_mangle]
@@ -1149,7 +1155,13 @@ mod export {
11491155 pub extern "C" fn config_getWorkers ( config : * const ConfigOptions ) -> libc:: c_uint {
11501156 assert ! ( !config. is_null( ) ) ;
11511157 let config = unsafe { & * config } ;
1152- config. general . workers . unwrap ( )
1158+ match & config. experimental . worker_threads {
1159+ Some ( w) => * w,
1160+ None => {
1161+ // By default use 1 worker per host.
1162+ config. hosts . len ( ) . try_into ( ) . unwrap ( )
1163+ }
1164+ }
11531165 }
11541166
11551167 #[ no_mangle]
0 commit comments