Skip to content

Commit 5022b8a

Browse files
committed
scftorture: Implement weighted primitive selection
This commit uses the scftorture.weight* kernel parameters to randomly chooses between smp_call_function_single(), smp_call_function_many(), and smp_call_function(). For each variant, it also randomly chooses whether to invoke it synchronously (wait=1) or asynchronously (wait=0). The percentage weighting for each option are dumped to the console log (search for "scf_sel_dump"). This accumulates statistics, which a later commit will dump out at the end of the run. Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent 80c9476 commit 5022b8a

1 file changed

Lines changed: 155 additions & 27 deletions

File tree

kernel/scftorture.c

Lines changed: 155 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ torture_param(bool, use_cpus_read_lock, 0, "Use cpus_read_lock() to exclude CPU
6464
torture_param(int, verbose, 0, "Enable verbose debugging printk()s");
6565
torture_param(int, weight_single, -1, "Testing weight for single-CPU no-wait operations.");
6666
torture_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.");
6969
torture_param(int, weight_all, -1, "Testing weight for all-CPU no-wait operations.");
7070
torture_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;
9496
static struct task_struct *scf_torture_stats_task;
9597
static 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.
98121
static atomic_t n_started;
99122
static 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
222336
scftorture_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

229343
static 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

Comments
 (0)