@@ -64,8 +64,8 @@ torture_param(bool, use_cpus_read_lock, 0, "Use cpus_read_lock() to exclude CPU
6464torture_param (int , verbose , 0 , "Enable verbose debugging printk()s" );
6565torture_param (int , weight_single , -1 , "Testing weight for single-CPU no-wait operations." );
6666torture_param (int , weight_single_wait , -1 , "Testing weight for single-CPU operations." );
67- torture_param (int , weight_mult , -1 , "Testing weight for multi-CPU no-wait operations." );
68- torture_param (int , weight_mult_wait , -1 , "Testing weight for multi-CPU operations." );
67+ torture_param (int , weight_many , -1 , "Testing weight for multi-CPU no-wait operations." );
68+ torture_param (int , weight_many_wait , -1 , "Testing weight for multi-CPU operations." );
6969torture_param (int , weight_all , -1 , "Testing weight for all-CPU no-wait operations." );
7070torture_param (int , weight_all_wait , -1 , "Testing weight for all-CPU operations." );
7171
@@ -83,9 +83,11 @@ struct scf_statistics {
8383 struct task_struct * task ;
8484 int cpu ;
8585 long long n_single ;
86+ long long n_single_ofl ;
8687 long long n_single_wait ;
87- long long n_multi ;
88- long long n_multi_wait ;
88+ long long n_single_wait_ofl ;
89+ long long n_many ;
90+ long long n_many_wait ;
8991 long long n_all ;
9092 long long n_all_wait ;
9193};
@@ -94,6 +96,27 @@ static struct scf_statistics *scf_stats_p;
9496static struct task_struct * scf_torture_stats_task ;
9597static DEFINE_PER_CPU (long long, scf_invoked_count ) ;
9698
99+ // Data for random primitive selection
100+ #define SCF_PRIM_SINGLE 0
101+ #define SCF_PRIM_MANY 1
102+ #define SCF_PRIM_ALL 2
103+ #define SCF_NPRIMS (2 * 3) // Need wait and no-wait versions of each.
104+
105+ static char * scf_prim_name [] = {
106+ "smp_call_function_single" ,
107+ "smp_call_function_many" ,
108+ "smp_call_function" ,
109+ };
110+
111+ struct scf_selector {
112+ unsigned long scfs_weight ;
113+ int scfs_prim ;
114+ bool scfs_wait ;
115+ };
116+ static struct scf_selector scf_sel_array [SCF_NPRIMS ];
117+ static int scf_sel_array_len ;
118+ static unsigned long scf_sel_totweight ;
119+
97120// Use to wait for all threads to start.
98121static atomic_t n_started ;
99122static atomic_t n_errs ;
@@ -131,6 +154,57 @@ scf_torture_stats(void *arg)
131154 return 0 ;
132155}
133156
157+ // Add a primitive to the scf_sel_array[].
158+ static void scf_sel_add (unsigned long weight , int prim , bool wait )
159+ {
160+ struct scf_selector * scfsp = & scf_sel_array [scf_sel_array_len ];
161+
162+ // If no weight, if array would overflow, if computing three-place
163+ // percentages would overflow, or if the scf_prim_name[] array would
164+ // overflow, don't bother. In the last three two cases, complain.
165+ if (!weight ||
166+ WARN_ON_ONCE (scf_sel_array_len >= ARRAY_SIZE (scf_sel_array )) ||
167+ WARN_ON_ONCE (0 - 100000 * weight <= 100000 * scf_sel_totweight ) ||
168+ WARN_ON_ONCE (prim >= ARRAY_SIZE (scf_prim_name )))
169+ return ;
170+ scf_sel_totweight += weight ;
171+ scfsp -> scfs_weight = scf_sel_totweight ;
172+ scfsp -> scfs_prim = prim ;
173+ scfsp -> scfs_wait = wait ;
174+ scf_sel_array_len ++ ;
175+ }
176+
177+ // Dump out weighting percentages for scf_prim_name[] array.
178+ static void scf_sel_dump (void )
179+ {
180+ int i ;
181+ unsigned long oldw = 0 ;
182+ struct scf_selector * scfsp ;
183+ unsigned long w ;
184+
185+ for (i = 0 ; i < scf_sel_array_len ; i ++ ) {
186+ scfsp = & scf_sel_array [i ];
187+ w = (scfsp -> scfs_weight - oldw ) * 100000 / scf_sel_totweight ;
188+ pr_info ("%s: %3lu.%03lu %s(%s)\n" , __func__ , w / 1000 , w % 1000 ,
189+ scf_prim_name [scfsp -> scfs_prim ],
190+ scfsp -> scfs_wait ? "wait" : "nowait" );
191+ oldw = scfsp -> scfs_weight ;
192+ }
193+ }
194+
195+ // Randomly pick a primitive and wait/nowait, based on weightings.
196+ static struct scf_selector * scf_sel_rand (struct torture_random_state * trsp )
197+ {
198+ int i ;
199+ unsigned long w = torture_random (trsp ) % (scf_sel_totweight + 1 );
200+
201+ for (i = 0 ; i < scf_sel_array_len ; i ++ )
202+ if (scf_sel_array [i ].scfs_weight >= w )
203+ return & scf_sel_array [i ];
204+ WARN_ON_ONCE (1 );
205+ return & scf_sel_array [0 ];
206+ }
207+
134208// Update statistics and occasionally burn up mass quantities of CPU time,
135209// if told to do so via scftorture.longwait. Otherwise, occasionally burn
136210// a little bit.
@@ -162,15 +236,55 @@ static void scf_handler(void *unused)
162236 }
163237}
164238
239+ // As above, but check for correct CPU.
240+ static void scf_handler_1 (void * me )
241+ {
242+ if (WARN_ON_ONCE (smp_processor_id () != (uintptr_t )me ))
243+ atomic_inc (& n_errs );
244+ scf_handler (NULL );
245+ }
246+
165247// Randomly do an smp_call_function*() invocation.
166- static void scftorture_invoke_one (struct scf_statistics * scfp ,struct torture_random_state * trsp )
248+ static void scftorture_invoke_one (struct scf_statistics * scfp , struct torture_random_state * trsp )
167249{
250+ uintptr_t cpu ;
251+ int ret ;
252+ struct scf_selector * scfsp = scf_sel_rand (trsp );
253+
168254 if (use_cpus_read_lock )
169255 cpus_read_lock ();
170256 else
171257 preempt_disable ();
172- scfp -> n_all ++ ;
173- smp_call_function (scf_handler , NULL , 0 );
258+ switch (scfsp -> scfs_prim ) {
259+ case SCF_PRIM_SINGLE :
260+ cpu = torture_random (trsp ) % nr_cpu_ids ;
261+ if (scfsp -> scfs_wait )
262+ scfp -> n_single_wait ++ ;
263+ else
264+ scfp -> n_single ++ ;
265+ ret = smp_call_function_single (cpu , scf_handler_1 , (void * )cpu , scfsp -> scfs_wait );
266+ if (ret ) {
267+ if (scfsp -> scfs_wait )
268+ scfp -> n_single_wait_ofl ++ ;
269+ else
270+ scfp -> n_single_ofl ++ ;
271+ }
272+ break ;
273+ case SCF_PRIM_MANY :
274+ if (scfsp -> scfs_wait )
275+ scfp -> n_many_wait ++ ;
276+ else
277+ scfp -> n_many ++ ;
278+ smp_call_function_many (cpu_online_mask , scf_handler , NULL , scfsp -> scfs_wait );
279+ break ;
280+ case SCF_PRIM_ALL :
281+ if (scfsp -> scfs_wait )
282+ scfp -> n_all_wait ++ ;
283+ else
284+ scfp -> n_all ++ ;
285+ smp_call_function (scf_handler , NULL , scfsp -> scfs_wait );
286+ break ;
287+ }
174288 if (use_cpus_read_lock )
175289 cpus_read_unlock ();
176290 else
@@ -222,8 +336,8 @@ static void
222336scftorture_print_module_parms (const char * tag )
223337{
224338 pr_alert (SCFTORT_FLAG
225- "--- %s: verbose=%d holdoff=%d longwait=%d nthreads=%d onoff_holdoff=%d onoff_interval=%d shutdown_secs=%d stat_interval=%d stutter_cpus=%d use_cpus_read_lock=%d, weight_single=%d, weight_single_wait=%d, weight_mult =%d, weight_mult_wait =%d, weight_all=%d, weight_all_wait=%d\n" , tag ,
226- verbose , holdoff , longwait , nthreads , onoff_holdoff , onoff_interval , shutdown , stat_interval , stutter_cpus , use_cpus_read_lock , weight_single , weight_single_wait , weight_mult , weight_mult_wait , weight_all , weight_all_wait );
339+ "--- %s: verbose=%d holdoff=%d longwait=%d nthreads=%d onoff_holdoff=%d onoff_interval=%d shutdown_secs=%d stat_interval=%d stutter_cpus=%d use_cpus_read_lock=%d, weight_single=%d, weight_single_wait=%d, weight_many =%d, weight_many_wait =%d, weight_all=%d, weight_all_wait=%d\n" , tag ,
340+ verbose , holdoff , longwait , nthreads , onoff_holdoff , onoff_interval , shutdown , stat_interval , stutter_cpus , use_cpus_read_lock , weight_single , weight_single_wait , weight_many , weight_many_wait , weight_all , weight_all_wait );
227341}
228342
229343static void scf_cleanup_handler (void * unused )
@@ -264,41 +378,55 @@ static int __init scf_torture_init(void)
264378{
265379 long i ;
266380 int firsterr = 0 ;
381+ unsigned long weight_single1 = weight_single ;
382+ unsigned long weight_single_wait1 = weight_single_wait ;
383+ unsigned long weight_many1 = weight_many ;
384+ unsigned long weight_many_wait1 = weight_many_wait ;
385+ unsigned long weight_all1 = weight_all ;
386+ unsigned long weight_all_wait1 = weight_all_wait ;
267387
268388 if (!torture_init_begin (SCFTORT_STRING , verbose ))
269389 return - EBUSY ;
270390
271391 scftorture_print_module_parms ("Start of test" );
272392
273393 if (weight_single == -1 && weight_single_wait == -1 &&
274- weight_mult == -1 && weight_mult_wait == -1 &&
394+ weight_many == -1 && weight_many_wait == -1 &&
275395 weight_all == -1 && weight_all_wait == -1 ) {
276- weight_single = 1 ;
277- weight_single_wait = 1 ;
278- weight_mult = 1 ;
279- weight_mult_wait = 1 ;
280- weight_all = 1 ;
281- weight_all_wait = 1 ;
396+ weight_single1 = 2 * nr_cpu_ids ;
397+ weight_single_wait1 = 2 * nr_cpu_ids ;
398+ weight_many1 = 2 ;
399+ weight_many_wait1 = 2 ;
400+ weight_all1 = 1 ;
401+ weight_all_wait1 = 1 ;
282402 } else {
283403 if (weight_single == -1 )
284- weight_single = 0 ;
404+ weight_single1 = 0 ;
285405 if (weight_single_wait == -1 )
286- weight_single_wait = 0 ;
287- if (weight_mult == -1 )
288- weight_mult = 0 ;
289- if (weight_mult_wait == -1 )
290- weight_mult_wait = 0 ;
406+ weight_single_wait1 = 0 ;
407+ if (weight_many == -1 )
408+ weight_many1 = 0 ;
409+ if (weight_many_wait == -1 )
410+ weight_many_wait1 = 0 ;
291411 if (weight_all == -1 )
292- weight_all = 0 ;
412+ weight_all1 = 0 ;
293413 if (weight_all_wait == -1 )
294- weight_all_wait = 0 ;
414+ weight_all_wait1 = 0 ;
295415 }
296- if (weight_single == 0 && weight_single_wait == 0 &&
297- weight_mult == 0 && weight_mult_wait == 0 &&
298- weight_all == 0 && weight_all_wait == 0 ) {
416+ if (weight_single1 == 0 && weight_single_wait1 == 0 &&
417+ weight_many1 == 0 && weight_many_wait1 == 0 &&
418+ weight_all1 == 0 && weight_all_wait1 == 0 ) {
419+ VERBOSE_SCFTORTOUT_ERRSTRING ("all zero weights makes no sense" );
299420 firsterr = - EINVAL ;
300421 goto unwind ;
301422 }
423+ scf_sel_add (weight_single1 , SCF_PRIM_SINGLE , false);
424+ scf_sel_add (weight_single_wait1 , SCF_PRIM_SINGLE , true);
425+ scf_sel_add (weight_many1 , SCF_PRIM_MANY , false);
426+ scf_sel_add (weight_many_wait1 , SCF_PRIM_MANY , true);
427+ scf_sel_add (weight_all1 , SCF_PRIM_ALL , false);
428+ scf_sel_add (weight_all_wait1 , SCF_PRIM_ALL , true);
429+ scf_sel_dump ();
302430
303431 if (onoff_interval > 0 ) {
304432 firsterr = torture_onoff_init (onoff_holdoff * HZ , onoff_interval , NULL );
0 commit comments