0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) fmt
0011
0012 #include <linux/types.h>
0013 #include <linux/kernel.h>
0014 #include <linux/init.h>
0015 #include <linux/mm.h>
0016 #include <linux/module.h>
0017 #include <linux/kthread.h>
0018 #include <linux/err.h>
0019 #include <linux/spinlock.h>
0020 #include <linux/smp.h>
0021 #include <linux/rcupdate.h>
0022 #include <linux/interrupt.h>
0023 #include <linux/sched.h>
0024 #include <uapi/linux/sched/types.h>
0025 #include <linux/atomic.h>
0026 #include <linux/bitops.h>
0027 #include <linux/completion.h>
0028 #include <linux/moduleparam.h>
0029 #include <linux/percpu.h>
0030 #include <linux/notifier.h>
0031 #include <linux/reboot.h>
0032 #include <linux/freezer.h>
0033 #include <linux/cpu.h>
0034 #include <linux/delay.h>
0035 #include <linux/stat.h>
0036 #include <linux/srcu.h>
0037 #include <linux/slab.h>
0038 #include <asm/byteorder.h>
0039 #include <linux/torture.h>
0040 #include <linux/vmalloc.h>
0041 #include <linux/rcupdate_trace.h>
0042
0043 #include "rcu.h"
0044
0045 MODULE_LICENSE("GPL");
0046 MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
0047
0048 #define SCALE_FLAG "-scale:"
0049 #define SCALEOUT_STRING(s) \
0050 pr_alert("%s" SCALE_FLAG " %s\n", scale_type, s)
0051 #define VERBOSE_SCALEOUT_STRING(s) \
0052 do { if (verbose) pr_alert("%s" SCALE_FLAG " %s\n", scale_type, s); } while (0)
0053 #define SCALEOUT_ERRSTRING(s) \
0054 pr_alert("%s" SCALE_FLAG "!!! %s\n", scale_type, s)
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 #ifdef MODULE
0081 # define RCUSCALE_SHUTDOWN 0
0082 #else
0083 # define RCUSCALE_SHUTDOWN 1
0084 #endif
0085
0086 torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives");
0087 torture_param(int, gp_async_max, 1000, "Max # outstanding waits per reader");
0088 torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
0089 torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
0090 torture_param(int, nreaders, -1, "Number of RCU reader threads");
0091 torture_param(int, nwriters, -1, "Number of RCU updater threads");
0092 torture_param(bool, shutdown, RCUSCALE_SHUTDOWN,
0093 "Shutdown at end of scalability tests.");
0094 torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
0095 torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");
0096 torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() scale test?");
0097 torture_param(int, kfree_mult, 1, "Multiple of kfree_obj size to allocate.");
0098
0099 static char *scale_type = "rcu";
0100 module_param(scale_type, charp, 0444);
0101 MODULE_PARM_DESC(scale_type, "Type of RCU to scalability-test (rcu, srcu, ...)");
0102
0103 static int nrealreaders;
0104 static int nrealwriters;
0105 static struct task_struct **writer_tasks;
0106 static struct task_struct **reader_tasks;
0107 static struct task_struct *shutdown_task;
0108
0109 static u64 **writer_durations;
0110 static int *writer_n_durations;
0111 static atomic_t n_rcu_scale_reader_started;
0112 static atomic_t n_rcu_scale_writer_started;
0113 static atomic_t n_rcu_scale_writer_finished;
0114 static wait_queue_head_t shutdown_wq;
0115 static u64 t_rcu_scale_writer_started;
0116 static u64 t_rcu_scale_writer_finished;
0117 static unsigned long b_rcu_gp_test_started;
0118 static unsigned long b_rcu_gp_test_finished;
0119 static DEFINE_PER_CPU(atomic_t, n_async_inflight);
0120
0121 #define MAX_MEAS 10000
0122 #define MIN_MEAS 100
0123
0124
0125
0126
0127
0128 struct rcu_scale_ops {
0129 int ptype;
0130 void (*init)(void);
0131 void (*cleanup)(void);
0132 int (*readlock)(void);
0133 void (*readunlock)(int idx);
0134 unsigned long (*get_gp_seq)(void);
0135 unsigned long (*gp_diff)(unsigned long new, unsigned long old);
0136 unsigned long (*exp_completed)(void);
0137 void (*async)(struct rcu_head *head, rcu_callback_t func);
0138 void (*gp_barrier)(void);
0139 void (*sync)(void);
0140 void (*exp_sync)(void);
0141 const char *name;
0142 };
0143
0144 static struct rcu_scale_ops *cur_ops;
0145
0146
0147
0148
0149
0150 static int rcu_scale_read_lock(void) __acquires(RCU)
0151 {
0152 rcu_read_lock();
0153 return 0;
0154 }
0155
0156 static void rcu_scale_read_unlock(int idx) __releases(RCU)
0157 {
0158 rcu_read_unlock();
0159 }
0160
0161 static unsigned long __maybe_unused rcu_no_completed(void)
0162 {
0163 return 0;
0164 }
0165
0166 static void rcu_sync_scale_init(void)
0167 {
0168 }
0169
0170 static struct rcu_scale_ops rcu_ops = {
0171 .ptype = RCU_FLAVOR,
0172 .init = rcu_sync_scale_init,
0173 .readlock = rcu_scale_read_lock,
0174 .readunlock = rcu_scale_read_unlock,
0175 .get_gp_seq = rcu_get_gp_seq,
0176 .gp_diff = rcu_seq_diff,
0177 .exp_completed = rcu_exp_batches_completed,
0178 .async = call_rcu,
0179 .gp_barrier = rcu_barrier,
0180 .sync = synchronize_rcu,
0181 .exp_sync = synchronize_rcu_expedited,
0182 .name = "rcu"
0183 };
0184
0185
0186
0187
0188
0189 DEFINE_STATIC_SRCU(srcu_ctl_scale);
0190 static struct srcu_struct *srcu_ctlp = &srcu_ctl_scale;
0191
0192 static int srcu_scale_read_lock(void) __acquires(srcu_ctlp)
0193 {
0194 return srcu_read_lock(srcu_ctlp);
0195 }
0196
0197 static void srcu_scale_read_unlock(int idx) __releases(srcu_ctlp)
0198 {
0199 srcu_read_unlock(srcu_ctlp, idx);
0200 }
0201
0202 static unsigned long srcu_scale_completed(void)
0203 {
0204 return srcu_batches_completed(srcu_ctlp);
0205 }
0206
0207 static void srcu_call_rcu(struct rcu_head *head, rcu_callback_t func)
0208 {
0209 call_srcu(srcu_ctlp, head, func);
0210 }
0211
0212 static void srcu_rcu_barrier(void)
0213 {
0214 srcu_barrier(srcu_ctlp);
0215 }
0216
0217 static void srcu_scale_synchronize(void)
0218 {
0219 synchronize_srcu(srcu_ctlp);
0220 }
0221
0222 static void srcu_scale_synchronize_expedited(void)
0223 {
0224 synchronize_srcu_expedited(srcu_ctlp);
0225 }
0226
0227 static struct rcu_scale_ops srcu_ops = {
0228 .ptype = SRCU_FLAVOR,
0229 .init = rcu_sync_scale_init,
0230 .readlock = srcu_scale_read_lock,
0231 .readunlock = srcu_scale_read_unlock,
0232 .get_gp_seq = srcu_scale_completed,
0233 .gp_diff = rcu_seq_diff,
0234 .exp_completed = srcu_scale_completed,
0235 .async = srcu_call_rcu,
0236 .gp_barrier = srcu_rcu_barrier,
0237 .sync = srcu_scale_synchronize,
0238 .exp_sync = srcu_scale_synchronize_expedited,
0239 .name = "srcu"
0240 };
0241
0242 static struct srcu_struct srcud;
0243
0244 static void srcu_sync_scale_init(void)
0245 {
0246 srcu_ctlp = &srcud;
0247 init_srcu_struct(srcu_ctlp);
0248 }
0249
0250 static void srcu_sync_scale_cleanup(void)
0251 {
0252 cleanup_srcu_struct(srcu_ctlp);
0253 }
0254
0255 static struct rcu_scale_ops srcud_ops = {
0256 .ptype = SRCU_FLAVOR,
0257 .init = srcu_sync_scale_init,
0258 .cleanup = srcu_sync_scale_cleanup,
0259 .readlock = srcu_scale_read_lock,
0260 .readunlock = srcu_scale_read_unlock,
0261 .get_gp_seq = srcu_scale_completed,
0262 .gp_diff = rcu_seq_diff,
0263 .exp_completed = srcu_scale_completed,
0264 .async = srcu_call_rcu,
0265 .gp_barrier = srcu_rcu_barrier,
0266 .sync = srcu_scale_synchronize,
0267 .exp_sync = srcu_scale_synchronize_expedited,
0268 .name = "srcud"
0269 };
0270
0271 #ifdef CONFIG_TASKS_RCU
0272
0273
0274
0275
0276
0277 static int tasks_scale_read_lock(void)
0278 {
0279 return 0;
0280 }
0281
0282 static void tasks_scale_read_unlock(int idx)
0283 {
0284 }
0285
0286 static struct rcu_scale_ops tasks_ops = {
0287 .ptype = RCU_TASKS_FLAVOR,
0288 .init = rcu_sync_scale_init,
0289 .readlock = tasks_scale_read_lock,
0290 .readunlock = tasks_scale_read_unlock,
0291 .get_gp_seq = rcu_no_completed,
0292 .gp_diff = rcu_seq_diff,
0293 .async = call_rcu_tasks,
0294 .gp_barrier = rcu_barrier_tasks,
0295 .sync = synchronize_rcu_tasks,
0296 .exp_sync = synchronize_rcu_tasks,
0297 .name = "tasks"
0298 };
0299
0300 #define TASKS_OPS &tasks_ops,
0301
0302 #else
0303
0304 #define TASKS_OPS
0305
0306 #endif
0307
0308 #ifdef CONFIG_TASKS_TRACE_RCU
0309
0310
0311
0312
0313
0314 static int tasks_trace_scale_read_lock(void)
0315 {
0316 rcu_read_lock_trace();
0317 return 0;
0318 }
0319
0320 static void tasks_trace_scale_read_unlock(int idx)
0321 {
0322 rcu_read_unlock_trace();
0323 }
0324
0325 static struct rcu_scale_ops tasks_tracing_ops = {
0326 .ptype = RCU_TASKS_FLAVOR,
0327 .init = rcu_sync_scale_init,
0328 .readlock = tasks_trace_scale_read_lock,
0329 .readunlock = tasks_trace_scale_read_unlock,
0330 .get_gp_seq = rcu_no_completed,
0331 .gp_diff = rcu_seq_diff,
0332 .async = call_rcu_tasks_trace,
0333 .gp_barrier = rcu_barrier_tasks_trace,
0334 .sync = synchronize_rcu_tasks_trace,
0335 .exp_sync = synchronize_rcu_tasks_trace,
0336 .name = "tasks-tracing"
0337 };
0338
0339 #define TASKS_TRACING_OPS &tasks_tracing_ops,
0340
0341 #else
0342
0343 #define TASKS_TRACING_OPS
0344
0345 #endif
0346
0347 static unsigned long rcuscale_seq_diff(unsigned long new, unsigned long old)
0348 {
0349 if (!cur_ops->gp_diff)
0350 return new - old;
0351 return cur_ops->gp_diff(new, old);
0352 }
0353
0354
0355
0356
0357 static void rcu_scale_wait_shutdown(void)
0358 {
0359 cond_resched_tasks_rcu_qs();
0360 if (atomic_read(&n_rcu_scale_writer_finished) < nrealwriters)
0361 return;
0362 while (!torture_must_stop())
0363 schedule_timeout_uninterruptible(1);
0364 }
0365
0366
0367
0368
0369
0370
0371
0372 static int
0373 rcu_scale_reader(void *arg)
0374 {
0375 unsigned long flags;
0376 int idx;
0377 long me = (long)arg;
0378
0379 VERBOSE_SCALEOUT_STRING("rcu_scale_reader task started");
0380 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
0381 set_user_nice(current, MAX_NICE);
0382 atomic_inc(&n_rcu_scale_reader_started);
0383
0384 do {
0385 local_irq_save(flags);
0386 idx = cur_ops->readlock();
0387 cur_ops->readunlock(idx);
0388 local_irq_restore(flags);
0389 rcu_scale_wait_shutdown();
0390 } while (!torture_must_stop());
0391 torture_kthread_stopping("rcu_scale_reader");
0392 return 0;
0393 }
0394
0395
0396
0397
0398 static void rcu_scale_async_cb(struct rcu_head *rhp)
0399 {
0400 atomic_dec(this_cpu_ptr(&n_async_inflight));
0401 kfree(rhp);
0402 }
0403
0404
0405
0406
0407 static int
0408 rcu_scale_writer(void *arg)
0409 {
0410 int i = 0;
0411 int i_max;
0412 long me = (long)arg;
0413 struct rcu_head *rhp = NULL;
0414 bool started = false, done = false, alldone = false;
0415 u64 t;
0416 u64 *wdp;
0417 u64 *wdpp = writer_durations[me];
0418
0419 VERBOSE_SCALEOUT_STRING("rcu_scale_writer task started");
0420 WARN_ON(!wdpp);
0421 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
0422 current->flags |= PF_NO_SETAFFINITY;
0423 sched_set_fifo_low(current);
0424
0425 if (holdoff)
0426 schedule_timeout_uninterruptible(holdoff * HZ);
0427
0428
0429
0430
0431
0432
0433 while (!gp_exp && system_state != SYSTEM_RUNNING)
0434 schedule_timeout_uninterruptible(1);
0435
0436 t = ktime_get_mono_fast_ns();
0437 if (atomic_inc_return(&n_rcu_scale_writer_started) >= nrealwriters) {
0438 t_rcu_scale_writer_started = t;
0439 if (gp_exp) {
0440 b_rcu_gp_test_started =
0441 cur_ops->exp_completed() / 2;
0442 } else {
0443 b_rcu_gp_test_started = cur_ops->get_gp_seq();
0444 }
0445 }
0446
0447 do {
0448 if (writer_holdoff)
0449 udelay(writer_holdoff);
0450 wdp = &wdpp[i];
0451 *wdp = ktime_get_mono_fast_ns();
0452 if (gp_async) {
0453 retry:
0454 if (!rhp)
0455 rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
0456 if (rhp && atomic_read(this_cpu_ptr(&n_async_inflight)) < gp_async_max) {
0457 atomic_inc(this_cpu_ptr(&n_async_inflight));
0458 cur_ops->async(rhp, rcu_scale_async_cb);
0459 rhp = NULL;
0460 } else if (!kthread_should_stop()) {
0461 cur_ops->gp_barrier();
0462 goto retry;
0463 } else {
0464 kfree(rhp);
0465 }
0466 } else if (gp_exp) {
0467 cur_ops->exp_sync();
0468 } else {
0469 cur_ops->sync();
0470 }
0471 t = ktime_get_mono_fast_ns();
0472 *wdp = t - *wdp;
0473 i_max = i;
0474 if (!started &&
0475 atomic_read(&n_rcu_scale_writer_started) >= nrealwriters)
0476 started = true;
0477 if (!done && i >= MIN_MEAS) {
0478 done = true;
0479 sched_set_normal(current, 0);
0480 pr_alert("%s%s rcu_scale_writer %ld has %d measurements\n",
0481 scale_type, SCALE_FLAG, me, MIN_MEAS);
0482 if (atomic_inc_return(&n_rcu_scale_writer_finished) >=
0483 nrealwriters) {
0484 schedule_timeout_interruptible(10);
0485 rcu_ftrace_dump(DUMP_ALL);
0486 SCALEOUT_STRING("Test complete");
0487 t_rcu_scale_writer_finished = t;
0488 if (gp_exp) {
0489 b_rcu_gp_test_finished =
0490 cur_ops->exp_completed() / 2;
0491 } else {
0492 b_rcu_gp_test_finished =
0493 cur_ops->get_gp_seq();
0494 }
0495 if (shutdown) {
0496 smp_mb();
0497 wake_up(&shutdown_wq);
0498 }
0499 }
0500 }
0501 if (done && !alldone &&
0502 atomic_read(&n_rcu_scale_writer_finished) >= nrealwriters)
0503 alldone = true;
0504 if (started && !alldone && i < MAX_MEAS - 1)
0505 i++;
0506 rcu_scale_wait_shutdown();
0507 } while (!torture_must_stop());
0508 if (gp_async) {
0509 cur_ops->gp_barrier();
0510 }
0511 writer_n_durations[me] = i_max + 1;
0512 torture_kthread_stopping("rcu_scale_writer");
0513 return 0;
0514 }
0515
0516 static void
0517 rcu_scale_print_module_parms(struct rcu_scale_ops *cur_ops, const char *tag)
0518 {
0519 pr_alert("%s" SCALE_FLAG
0520 "--- %s: nreaders=%d nwriters=%d verbose=%d shutdown=%d\n",
0521 scale_type, tag, nrealreaders, nrealwriters, verbose, shutdown);
0522 }
0523
0524 static void
0525 rcu_scale_cleanup(void)
0526 {
0527 int i;
0528 int j;
0529 int ngps = 0;
0530 u64 *wdp;
0531 u64 *wdpp;
0532
0533
0534
0535
0536
0537 if (rcu_gp_is_expedited() && !rcu_gp_is_normal() && !gp_exp)
0538 SCALEOUT_ERRSTRING("All grace periods expedited, no normal ones to measure!");
0539 if (rcu_gp_is_normal() && gp_exp)
0540 SCALEOUT_ERRSTRING("All grace periods normal, no expedited ones to measure!");
0541 if (gp_exp && gp_async)
0542 SCALEOUT_ERRSTRING("No expedited async GPs, so went with async!");
0543
0544 if (torture_cleanup_begin())
0545 return;
0546 if (!cur_ops) {
0547 torture_cleanup_end();
0548 return;
0549 }
0550
0551 if (reader_tasks) {
0552 for (i = 0; i < nrealreaders; i++)
0553 torture_stop_kthread(rcu_scale_reader,
0554 reader_tasks[i]);
0555 kfree(reader_tasks);
0556 }
0557
0558 if (writer_tasks) {
0559 for (i = 0; i < nrealwriters; i++) {
0560 torture_stop_kthread(rcu_scale_writer,
0561 writer_tasks[i]);
0562 if (!writer_n_durations)
0563 continue;
0564 j = writer_n_durations[i];
0565 pr_alert("%s%s writer %d gps: %d\n",
0566 scale_type, SCALE_FLAG, i, j);
0567 ngps += j;
0568 }
0569 pr_alert("%s%s start: %llu end: %llu duration: %llu gps: %d batches: %ld\n",
0570 scale_type, SCALE_FLAG,
0571 t_rcu_scale_writer_started, t_rcu_scale_writer_finished,
0572 t_rcu_scale_writer_finished -
0573 t_rcu_scale_writer_started,
0574 ngps,
0575 rcuscale_seq_diff(b_rcu_gp_test_finished,
0576 b_rcu_gp_test_started));
0577 for (i = 0; i < nrealwriters; i++) {
0578 if (!writer_durations)
0579 break;
0580 if (!writer_n_durations)
0581 continue;
0582 wdpp = writer_durations[i];
0583 if (!wdpp)
0584 continue;
0585 for (j = 0; j < writer_n_durations[i]; j++) {
0586 wdp = &wdpp[j];
0587 pr_alert("%s%s %4d writer-duration: %5d %llu\n",
0588 scale_type, SCALE_FLAG,
0589 i, j, *wdp);
0590 if (j % 100 == 0)
0591 schedule_timeout_uninterruptible(1);
0592 }
0593 kfree(writer_durations[i]);
0594 }
0595 kfree(writer_tasks);
0596 kfree(writer_durations);
0597 kfree(writer_n_durations);
0598 }
0599
0600
0601 if (cur_ops->cleanup != NULL)
0602 cur_ops->cleanup();
0603
0604 torture_cleanup_end();
0605 }
0606
0607
0608
0609
0610
0611
0612 static int compute_real(int n)
0613 {
0614 int nr;
0615
0616 if (n >= 0) {
0617 nr = n;
0618 } else {
0619 nr = num_online_cpus() + 1 + n;
0620 if (nr <= 0)
0621 nr = 1;
0622 }
0623 return nr;
0624 }
0625
0626
0627
0628
0629
0630 static int
0631 rcu_scale_shutdown(void *arg)
0632 {
0633 wait_event(shutdown_wq,
0634 atomic_read(&n_rcu_scale_writer_finished) >= nrealwriters);
0635 smp_mb();
0636 rcu_scale_cleanup();
0637 kernel_power_off();
0638 return -EINVAL;
0639 }
0640
0641
0642
0643
0644
0645
0646 torture_param(int, kfree_nthreads, -1, "Number of threads running loops of kfree_rcu().");
0647 torture_param(int, kfree_alloc_num, 8000, "Number of allocations and frees done in an iteration.");
0648 torture_param(int, kfree_loops, 10, "Number of loops doing kfree_alloc_num allocations and frees.");
0649 torture_param(bool, kfree_rcu_test_double, false, "Do we run a kfree_rcu() double-argument scale test?");
0650 torture_param(bool, kfree_rcu_test_single, false, "Do we run a kfree_rcu() single-argument scale test?");
0651
0652 static struct task_struct **kfree_reader_tasks;
0653 static int kfree_nrealthreads;
0654 static atomic_t n_kfree_scale_thread_started;
0655 static atomic_t n_kfree_scale_thread_ended;
0656
0657 struct kfree_obj {
0658 char kfree_obj[8];
0659 struct rcu_head rh;
0660 };
0661
0662 static int
0663 kfree_scale_thread(void *arg)
0664 {
0665 int i, loop = 0;
0666 long me = (long)arg;
0667 struct kfree_obj *alloc_ptr;
0668 u64 start_time, end_time;
0669 long long mem_begin, mem_during = 0;
0670 bool kfree_rcu_test_both;
0671 DEFINE_TORTURE_RANDOM(tr);
0672
0673 VERBOSE_SCALEOUT_STRING("kfree_scale_thread task started");
0674 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
0675 set_user_nice(current, MAX_NICE);
0676 kfree_rcu_test_both = (kfree_rcu_test_single == kfree_rcu_test_double);
0677
0678 start_time = ktime_get_mono_fast_ns();
0679
0680 if (atomic_inc_return(&n_kfree_scale_thread_started) >= kfree_nrealthreads) {
0681 if (gp_exp)
0682 b_rcu_gp_test_started = cur_ops->exp_completed() / 2;
0683 else
0684 b_rcu_gp_test_started = cur_ops->get_gp_seq();
0685 }
0686
0687 do {
0688 if (!mem_during) {
0689 mem_during = mem_begin = si_mem_available();
0690 } else if (loop % (kfree_loops / 4) == 0) {
0691 mem_during = (mem_during + si_mem_available()) / 2;
0692 }
0693
0694 for (i = 0; i < kfree_alloc_num; i++) {
0695 alloc_ptr = kmalloc(kfree_mult * sizeof(struct kfree_obj), GFP_KERNEL);
0696 if (!alloc_ptr)
0697 return -ENOMEM;
0698
0699
0700
0701
0702
0703 if ((kfree_rcu_test_single && !kfree_rcu_test_double) ||
0704 (kfree_rcu_test_both && torture_random(&tr) & 0x800))
0705 kfree_rcu(alloc_ptr);
0706 else
0707 kfree_rcu(alloc_ptr, rh);
0708 }
0709
0710 cond_resched();
0711 } while (!torture_must_stop() && ++loop < kfree_loops);
0712
0713 if (atomic_inc_return(&n_kfree_scale_thread_ended) >= kfree_nrealthreads) {
0714 end_time = ktime_get_mono_fast_ns();
0715
0716 if (gp_exp)
0717 b_rcu_gp_test_finished = cur_ops->exp_completed() / 2;
0718 else
0719 b_rcu_gp_test_finished = cur_ops->get_gp_seq();
0720
0721 pr_alert("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld, memory footprint: %lldMB\n",
0722 (unsigned long long)(end_time - start_time), kfree_loops,
0723 rcuscale_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started),
0724 (mem_begin - mem_during) >> (20 - PAGE_SHIFT));
0725
0726 if (shutdown) {
0727 smp_mb();
0728 wake_up(&shutdown_wq);
0729 }
0730 }
0731
0732 torture_kthread_stopping("kfree_scale_thread");
0733 return 0;
0734 }
0735
0736 static void
0737 kfree_scale_cleanup(void)
0738 {
0739 int i;
0740
0741 if (torture_cleanup_begin())
0742 return;
0743
0744 if (kfree_reader_tasks) {
0745 for (i = 0; i < kfree_nrealthreads; i++)
0746 torture_stop_kthread(kfree_scale_thread,
0747 kfree_reader_tasks[i]);
0748 kfree(kfree_reader_tasks);
0749 }
0750
0751 torture_cleanup_end();
0752 }
0753
0754
0755
0756
0757 static int
0758 kfree_scale_shutdown(void *arg)
0759 {
0760 wait_event(shutdown_wq,
0761 atomic_read(&n_kfree_scale_thread_ended) >= kfree_nrealthreads);
0762
0763 smp_mb();
0764
0765 kfree_scale_cleanup();
0766 kernel_power_off();
0767 return -EINVAL;
0768 }
0769
0770 static int __init
0771 kfree_scale_init(void)
0772 {
0773 long i;
0774 int firsterr = 0;
0775
0776 kfree_nrealthreads = compute_real(kfree_nthreads);
0777
0778 if (shutdown) {
0779 init_waitqueue_head(&shutdown_wq);
0780 firsterr = torture_create_kthread(kfree_scale_shutdown, NULL,
0781 shutdown_task);
0782 if (torture_init_error(firsterr))
0783 goto unwind;
0784 schedule_timeout_uninterruptible(1);
0785 }
0786
0787 pr_alert("kfree object size=%zu\n", kfree_mult * sizeof(struct kfree_obj));
0788
0789 kfree_reader_tasks = kcalloc(kfree_nrealthreads, sizeof(kfree_reader_tasks[0]),
0790 GFP_KERNEL);
0791 if (kfree_reader_tasks == NULL) {
0792 firsterr = -ENOMEM;
0793 goto unwind;
0794 }
0795
0796 for (i = 0; i < kfree_nrealthreads; i++) {
0797 firsterr = torture_create_kthread(kfree_scale_thread, (void *)i,
0798 kfree_reader_tasks[i]);
0799 if (torture_init_error(firsterr))
0800 goto unwind;
0801 }
0802
0803 while (atomic_read(&n_kfree_scale_thread_started) < kfree_nrealthreads)
0804 schedule_timeout_uninterruptible(1);
0805
0806 torture_init_end();
0807 return 0;
0808
0809 unwind:
0810 torture_init_end();
0811 kfree_scale_cleanup();
0812 return firsterr;
0813 }
0814
0815 static int __init
0816 rcu_scale_init(void)
0817 {
0818 long i;
0819 int firsterr = 0;
0820 static struct rcu_scale_ops *scale_ops[] = {
0821 &rcu_ops, &srcu_ops, &srcud_ops, TASKS_OPS TASKS_TRACING_OPS
0822 };
0823
0824 if (!torture_init_begin(scale_type, verbose))
0825 return -EBUSY;
0826
0827
0828 for (i = 0; i < ARRAY_SIZE(scale_ops); i++) {
0829 cur_ops = scale_ops[i];
0830 if (strcmp(scale_type, cur_ops->name) == 0)
0831 break;
0832 }
0833 if (i == ARRAY_SIZE(scale_ops)) {
0834 pr_alert("rcu-scale: invalid scale type: \"%s\"\n", scale_type);
0835 pr_alert("rcu-scale types:");
0836 for (i = 0; i < ARRAY_SIZE(scale_ops); i++)
0837 pr_cont(" %s", scale_ops[i]->name);
0838 pr_cont("\n");
0839 firsterr = -EINVAL;
0840 cur_ops = NULL;
0841 goto unwind;
0842 }
0843 if (cur_ops->init)
0844 cur_ops->init();
0845
0846 if (kfree_rcu_test)
0847 return kfree_scale_init();
0848
0849 nrealwriters = compute_real(nwriters);
0850 nrealreaders = compute_real(nreaders);
0851 atomic_set(&n_rcu_scale_reader_started, 0);
0852 atomic_set(&n_rcu_scale_writer_started, 0);
0853 atomic_set(&n_rcu_scale_writer_finished, 0);
0854 rcu_scale_print_module_parms(cur_ops, "Start of test");
0855
0856
0857
0858 if (shutdown) {
0859 init_waitqueue_head(&shutdown_wq);
0860 firsterr = torture_create_kthread(rcu_scale_shutdown, NULL,
0861 shutdown_task);
0862 if (torture_init_error(firsterr))
0863 goto unwind;
0864 schedule_timeout_uninterruptible(1);
0865 }
0866 reader_tasks = kcalloc(nrealreaders, sizeof(reader_tasks[0]),
0867 GFP_KERNEL);
0868 if (reader_tasks == NULL) {
0869 SCALEOUT_ERRSTRING("out of memory");
0870 firsterr = -ENOMEM;
0871 goto unwind;
0872 }
0873 for (i = 0; i < nrealreaders; i++) {
0874 firsterr = torture_create_kthread(rcu_scale_reader, (void *)i,
0875 reader_tasks[i]);
0876 if (torture_init_error(firsterr))
0877 goto unwind;
0878 }
0879 while (atomic_read(&n_rcu_scale_reader_started) < nrealreaders)
0880 schedule_timeout_uninterruptible(1);
0881 writer_tasks = kcalloc(nrealwriters, sizeof(reader_tasks[0]),
0882 GFP_KERNEL);
0883 writer_durations = kcalloc(nrealwriters, sizeof(*writer_durations),
0884 GFP_KERNEL);
0885 writer_n_durations =
0886 kcalloc(nrealwriters, sizeof(*writer_n_durations),
0887 GFP_KERNEL);
0888 if (!writer_tasks || !writer_durations || !writer_n_durations) {
0889 SCALEOUT_ERRSTRING("out of memory");
0890 firsterr = -ENOMEM;
0891 goto unwind;
0892 }
0893 for (i = 0; i < nrealwriters; i++) {
0894 writer_durations[i] =
0895 kcalloc(MAX_MEAS, sizeof(*writer_durations[i]),
0896 GFP_KERNEL);
0897 if (!writer_durations[i]) {
0898 firsterr = -ENOMEM;
0899 goto unwind;
0900 }
0901 firsterr = torture_create_kthread(rcu_scale_writer, (void *)i,
0902 writer_tasks[i]);
0903 if (torture_init_error(firsterr))
0904 goto unwind;
0905 }
0906 torture_init_end();
0907 return 0;
0908
0909 unwind:
0910 torture_init_end();
0911 rcu_scale_cleanup();
0912 if (shutdown) {
0913 WARN_ON(!IS_MODULE(CONFIG_RCU_SCALE_TEST));
0914 kernel_power_off();
0915 }
0916 return firsterr;
0917 }
0918
0919 module_init(rcu_scale_init);
0920 module_exit(rcu_scale_cleanup);