Linux 5.6.13
[linux/fpc-iii.git] / kernel / rcu / rcuperf.c
blobda94b89cd531078c54ddaacfb1dce4a4d770484d
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Read-Copy Update module-based performance-test facility
5 * Copyright (C) IBM Corporation, 2015
7 * Authors: Paul E. McKenney <paulmck@linux.ibm.com>
8 */
10 #define pr_fmt(fmt) fmt
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/module.h>
16 #include <linux/kthread.h>
17 #include <linux/err.h>
18 #include <linux/spinlock.h>
19 #include <linux/smp.h>
20 #include <linux/rcupdate.h>
21 #include <linux/interrupt.h>
22 #include <linux/sched.h>
23 #include <uapi/linux/sched/types.h>
24 #include <linux/atomic.h>
25 #include <linux/bitops.h>
26 #include <linux/completion.h>
27 #include <linux/moduleparam.h>
28 #include <linux/percpu.h>
29 #include <linux/notifier.h>
30 #include <linux/reboot.h>
31 #include <linux/freezer.h>
32 #include <linux/cpu.h>
33 #include <linux/delay.h>
34 #include <linux/stat.h>
35 #include <linux/srcu.h>
36 #include <linux/slab.h>
37 #include <asm/byteorder.h>
38 #include <linux/torture.h>
39 #include <linux/vmalloc.h>
41 #include "rcu.h"
43 MODULE_LICENSE("GPL");
44 MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
46 #define PERF_FLAG "-perf:"
47 #define PERFOUT_STRING(s) \
48 pr_alert("%s" PERF_FLAG " %s\n", perf_type, s)
49 #define VERBOSE_PERFOUT_STRING(s) \
50 do { if (verbose) pr_alert("%s" PERF_FLAG " %s\n", perf_type, s); } while (0)
51 #define VERBOSE_PERFOUT_ERRSTRING(s) \
52 do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } while (0)
55 * The intended use cases for the nreaders and nwriters module parameters
56 * are as follows:
58 * 1. Specify only the nr_cpus kernel boot parameter. This will
59 * set both nreaders and nwriters to the value specified by
60 * nr_cpus for a mixed reader/writer test.
62 * 2. Specify the nr_cpus kernel boot parameter, but set
63 * rcuperf.nreaders to zero. This will set nwriters to the
64 * value specified by nr_cpus for an update-only test.
66 * 3. Specify the nr_cpus kernel boot parameter, but set
67 * rcuperf.nwriters to zero. This will set nreaders to the
68 * value specified by nr_cpus for a read-only test.
70 * Various other use cases may of course be specified.
73 #ifdef MODULE
74 # define RCUPERF_SHUTDOWN 0
75 #else
76 # define RCUPERF_SHUTDOWN 1
77 #endif
79 torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives");
80 torture_param(int, gp_async_max, 1000, "Max # outstanding waits per reader");
81 torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
82 torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
83 torture_param(int, nreaders, -1, "Number of RCU reader threads");
84 torture_param(int, nwriters, -1, "Number of RCU updater threads");
85 torture_param(bool, shutdown, RCUPERF_SHUTDOWN,
86 "Shutdown at end of performance tests.");
87 torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
88 torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");
89 torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() perf test?");
91 static char *perf_type = "rcu";
92 module_param(perf_type, charp, 0444);
93 MODULE_PARM_DESC(perf_type, "Type of RCU to performance-test (rcu, srcu, ...)");
95 static int nrealreaders;
96 static int nrealwriters;
97 static struct task_struct **writer_tasks;
98 static struct task_struct **reader_tasks;
99 static struct task_struct *shutdown_task;
101 static u64 **writer_durations;
102 static int *writer_n_durations;
103 static atomic_t n_rcu_perf_reader_started;
104 static atomic_t n_rcu_perf_writer_started;
105 static atomic_t n_rcu_perf_writer_finished;
106 static wait_queue_head_t shutdown_wq;
107 static u64 t_rcu_perf_writer_started;
108 static u64 t_rcu_perf_writer_finished;
109 static unsigned long b_rcu_gp_test_started;
110 static unsigned long b_rcu_gp_test_finished;
111 static DEFINE_PER_CPU(atomic_t, n_async_inflight);
113 #define MAX_MEAS 10000
114 #define MIN_MEAS 100
117 * Operations vector for selecting different types of tests.
120 struct rcu_perf_ops {
121 int ptype;
122 void (*init)(void);
123 void (*cleanup)(void);
124 int (*readlock)(void);
125 void (*readunlock)(int idx);
126 unsigned long (*get_gp_seq)(void);
127 unsigned long (*gp_diff)(unsigned long new, unsigned long old);
128 unsigned long (*exp_completed)(void);
129 void (*async)(struct rcu_head *head, rcu_callback_t func);
130 void (*gp_barrier)(void);
131 void (*sync)(void);
132 void (*exp_sync)(void);
133 const char *name;
136 static struct rcu_perf_ops *cur_ops;
139 * Definitions for rcu perf testing.
142 static int rcu_perf_read_lock(void) __acquires(RCU)
144 rcu_read_lock();
145 return 0;
148 static void rcu_perf_read_unlock(int idx) __releases(RCU)
150 rcu_read_unlock();
153 static unsigned long __maybe_unused rcu_no_completed(void)
155 return 0;
158 static void rcu_sync_perf_init(void)
162 static struct rcu_perf_ops rcu_ops = {
163 .ptype = RCU_FLAVOR,
164 .init = rcu_sync_perf_init,
165 .readlock = rcu_perf_read_lock,
166 .readunlock = rcu_perf_read_unlock,
167 .get_gp_seq = rcu_get_gp_seq,
168 .gp_diff = rcu_seq_diff,
169 .exp_completed = rcu_exp_batches_completed,
170 .async = call_rcu,
171 .gp_barrier = rcu_barrier,
172 .sync = synchronize_rcu,
173 .exp_sync = synchronize_rcu_expedited,
174 .name = "rcu"
178 * Definitions for srcu perf testing.
181 DEFINE_STATIC_SRCU(srcu_ctl_perf);
182 static struct srcu_struct *srcu_ctlp = &srcu_ctl_perf;
184 static int srcu_perf_read_lock(void) __acquires(srcu_ctlp)
186 return srcu_read_lock(srcu_ctlp);
189 static void srcu_perf_read_unlock(int idx) __releases(srcu_ctlp)
191 srcu_read_unlock(srcu_ctlp, idx);
194 static unsigned long srcu_perf_completed(void)
196 return srcu_batches_completed(srcu_ctlp);
199 static void srcu_call_rcu(struct rcu_head *head, rcu_callback_t func)
201 call_srcu(srcu_ctlp, head, func);
204 static void srcu_rcu_barrier(void)
206 srcu_barrier(srcu_ctlp);
209 static void srcu_perf_synchronize(void)
211 synchronize_srcu(srcu_ctlp);
214 static void srcu_perf_synchronize_expedited(void)
216 synchronize_srcu_expedited(srcu_ctlp);
219 static struct rcu_perf_ops srcu_ops = {
220 .ptype = SRCU_FLAVOR,
221 .init = rcu_sync_perf_init,
222 .readlock = srcu_perf_read_lock,
223 .readunlock = srcu_perf_read_unlock,
224 .get_gp_seq = srcu_perf_completed,
225 .gp_diff = rcu_seq_diff,
226 .exp_completed = srcu_perf_completed,
227 .async = srcu_call_rcu,
228 .gp_barrier = srcu_rcu_barrier,
229 .sync = srcu_perf_synchronize,
230 .exp_sync = srcu_perf_synchronize_expedited,
231 .name = "srcu"
234 static struct srcu_struct srcud;
236 static void srcu_sync_perf_init(void)
238 srcu_ctlp = &srcud;
239 init_srcu_struct(srcu_ctlp);
242 static void srcu_sync_perf_cleanup(void)
244 cleanup_srcu_struct(srcu_ctlp);
247 static struct rcu_perf_ops srcud_ops = {
248 .ptype = SRCU_FLAVOR,
249 .init = srcu_sync_perf_init,
250 .cleanup = srcu_sync_perf_cleanup,
251 .readlock = srcu_perf_read_lock,
252 .readunlock = srcu_perf_read_unlock,
253 .get_gp_seq = srcu_perf_completed,
254 .gp_diff = rcu_seq_diff,
255 .exp_completed = srcu_perf_completed,
256 .async = srcu_call_rcu,
257 .gp_barrier = srcu_rcu_barrier,
258 .sync = srcu_perf_synchronize,
259 .exp_sync = srcu_perf_synchronize_expedited,
260 .name = "srcud"
264 * Definitions for RCU-tasks perf testing.
267 static int tasks_perf_read_lock(void)
269 return 0;
272 static void tasks_perf_read_unlock(int idx)
276 static struct rcu_perf_ops tasks_ops = {
277 .ptype = RCU_TASKS_FLAVOR,
278 .init = rcu_sync_perf_init,
279 .readlock = tasks_perf_read_lock,
280 .readunlock = tasks_perf_read_unlock,
281 .get_gp_seq = rcu_no_completed,
282 .gp_diff = rcu_seq_diff,
283 .async = call_rcu_tasks,
284 .gp_barrier = rcu_barrier_tasks,
285 .sync = synchronize_rcu_tasks,
286 .exp_sync = synchronize_rcu_tasks,
287 .name = "tasks"
290 static unsigned long rcuperf_seq_diff(unsigned long new, unsigned long old)
292 if (!cur_ops->gp_diff)
293 return new - old;
294 return cur_ops->gp_diff(new, old);
298 * If performance tests complete, wait for shutdown to commence.
300 static void rcu_perf_wait_shutdown(void)
302 cond_resched_tasks_rcu_qs();
303 if (atomic_read(&n_rcu_perf_writer_finished) < nrealwriters)
304 return;
305 while (!torture_must_stop())
306 schedule_timeout_uninterruptible(1);
310 * RCU perf reader kthread. Repeatedly does empty RCU read-side
311 * critical section, minimizing update-side interference.
313 static int
314 rcu_perf_reader(void *arg)
316 unsigned long flags;
317 int idx;
318 long me = (long)arg;
320 VERBOSE_PERFOUT_STRING("rcu_perf_reader task started");
321 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
322 set_user_nice(current, MAX_NICE);
323 atomic_inc(&n_rcu_perf_reader_started);
325 do {
326 local_irq_save(flags);
327 idx = cur_ops->readlock();
328 cur_ops->readunlock(idx);
329 local_irq_restore(flags);
330 rcu_perf_wait_shutdown();
331 } while (!torture_must_stop());
332 torture_kthread_stopping("rcu_perf_reader");
333 return 0;
337 * Callback function for asynchronous grace periods from rcu_perf_writer().
339 static void rcu_perf_async_cb(struct rcu_head *rhp)
341 atomic_dec(this_cpu_ptr(&n_async_inflight));
342 kfree(rhp);
346 * RCU perf writer kthread. Repeatedly does a grace period.
348 static int
349 rcu_perf_writer(void *arg)
351 int i = 0;
352 int i_max;
353 long me = (long)arg;
354 struct rcu_head *rhp = NULL;
355 struct sched_param sp;
356 bool started = false, done = false, alldone = false;
357 u64 t;
358 u64 *wdp;
359 u64 *wdpp = writer_durations[me];
361 VERBOSE_PERFOUT_STRING("rcu_perf_writer task started");
362 WARN_ON(!wdpp);
363 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
364 sp.sched_priority = 1;
365 sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
367 if (holdoff)
368 schedule_timeout_uninterruptible(holdoff * HZ);
371 * Wait until rcu_end_inkernel_boot() is called for normal GP tests
372 * so that RCU is not always expedited for normal GP tests.
373 * The system_state test is approximate, but works well in practice.
375 while (!gp_exp && system_state != SYSTEM_RUNNING)
376 schedule_timeout_uninterruptible(1);
378 t = ktime_get_mono_fast_ns();
379 if (atomic_inc_return(&n_rcu_perf_writer_started) >= nrealwriters) {
380 t_rcu_perf_writer_started = t;
381 if (gp_exp) {
382 b_rcu_gp_test_started =
383 cur_ops->exp_completed() / 2;
384 } else {
385 b_rcu_gp_test_started = cur_ops->get_gp_seq();
389 do {
390 if (writer_holdoff)
391 udelay(writer_holdoff);
392 wdp = &wdpp[i];
393 *wdp = ktime_get_mono_fast_ns();
394 if (gp_async) {
395 retry:
396 if (!rhp)
397 rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
398 if (rhp && atomic_read(this_cpu_ptr(&n_async_inflight)) < gp_async_max) {
399 atomic_inc(this_cpu_ptr(&n_async_inflight));
400 cur_ops->async(rhp, rcu_perf_async_cb);
401 rhp = NULL;
402 } else if (!kthread_should_stop()) {
403 cur_ops->gp_barrier();
404 goto retry;
405 } else {
406 kfree(rhp); /* Because we are stopping. */
408 } else if (gp_exp) {
409 cur_ops->exp_sync();
410 } else {
411 cur_ops->sync();
413 t = ktime_get_mono_fast_ns();
414 *wdp = t - *wdp;
415 i_max = i;
416 if (!started &&
417 atomic_read(&n_rcu_perf_writer_started) >= nrealwriters)
418 started = true;
419 if (!done && i >= MIN_MEAS) {
420 done = true;
421 sp.sched_priority = 0;
422 sched_setscheduler_nocheck(current,
423 SCHED_NORMAL, &sp);
424 pr_alert("%s%s rcu_perf_writer %ld has %d measurements\n",
425 perf_type, PERF_FLAG, me, MIN_MEAS);
426 if (atomic_inc_return(&n_rcu_perf_writer_finished) >=
427 nrealwriters) {
428 schedule_timeout_interruptible(10);
429 rcu_ftrace_dump(DUMP_ALL);
430 PERFOUT_STRING("Test complete");
431 t_rcu_perf_writer_finished = t;
432 if (gp_exp) {
433 b_rcu_gp_test_finished =
434 cur_ops->exp_completed() / 2;
435 } else {
436 b_rcu_gp_test_finished =
437 cur_ops->get_gp_seq();
439 if (shutdown) {
440 smp_mb(); /* Assign before wake. */
441 wake_up(&shutdown_wq);
445 if (done && !alldone &&
446 atomic_read(&n_rcu_perf_writer_finished) >= nrealwriters)
447 alldone = true;
448 if (started && !alldone && i < MAX_MEAS - 1)
449 i++;
450 rcu_perf_wait_shutdown();
451 } while (!torture_must_stop());
452 if (gp_async) {
453 cur_ops->gp_barrier();
455 writer_n_durations[me] = i_max;
456 torture_kthread_stopping("rcu_perf_writer");
457 return 0;
460 static void
461 rcu_perf_print_module_parms(struct rcu_perf_ops *cur_ops, const char *tag)
463 pr_alert("%s" PERF_FLAG
464 "--- %s: nreaders=%d nwriters=%d verbose=%d shutdown=%d\n",
465 perf_type, tag, nrealreaders, nrealwriters, verbose, shutdown);
468 static void
469 rcu_perf_cleanup(void)
471 int i;
472 int j;
473 int ngps = 0;
474 u64 *wdp;
475 u64 *wdpp;
478 * Would like warning at start, but everything is expedited
479 * during the mid-boot phase, so have to wait till the end.
481 if (rcu_gp_is_expedited() && !rcu_gp_is_normal() && !gp_exp)
482 VERBOSE_PERFOUT_ERRSTRING("All grace periods expedited, no normal ones to measure!");
483 if (rcu_gp_is_normal() && gp_exp)
484 VERBOSE_PERFOUT_ERRSTRING("All grace periods normal, no expedited ones to measure!");
485 if (gp_exp && gp_async)
486 VERBOSE_PERFOUT_ERRSTRING("No expedited async GPs, so went with async!");
488 if (torture_cleanup_begin())
489 return;
490 if (!cur_ops) {
491 torture_cleanup_end();
492 return;
495 if (reader_tasks) {
496 for (i = 0; i < nrealreaders; i++)
497 torture_stop_kthread(rcu_perf_reader,
498 reader_tasks[i]);
499 kfree(reader_tasks);
502 if (writer_tasks) {
503 for (i = 0; i < nrealwriters; i++) {
504 torture_stop_kthread(rcu_perf_writer,
505 writer_tasks[i]);
506 if (!writer_n_durations)
507 continue;
508 j = writer_n_durations[i];
509 pr_alert("%s%s writer %d gps: %d\n",
510 perf_type, PERF_FLAG, i, j);
511 ngps += j;
513 pr_alert("%s%s start: %llu end: %llu duration: %llu gps: %d batches: %ld\n",
514 perf_type, PERF_FLAG,
515 t_rcu_perf_writer_started, t_rcu_perf_writer_finished,
516 t_rcu_perf_writer_finished -
517 t_rcu_perf_writer_started,
518 ngps,
519 rcuperf_seq_diff(b_rcu_gp_test_finished,
520 b_rcu_gp_test_started));
521 for (i = 0; i < nrealwriters; i++) {
522 if (!writer_durations)
523 break;
524 if (!writer_n_durations)
525 continue;
526 wdpp = writer_durations[i];
527 if (!wdpp)
528 continue;
529 for (j = 0; j <= writer_n_durations[i]; j++) {
530 wdp = &wdpp[j];
531 pr_alert("%s%s %4d writer-duration: %5d %llu\n",
532 perf_type, PERF_FLAG,
533 i, j, *wdp);
534 if (j % 100 == 0)
535 schedule_timeout_uninterruptible(1);
537 kfree(writer_durations[i]);
539 kfree(writer_tasks);
540 kfree(writer_durations);
541 kfree(writer_n_durations);
544 /* Do torture-type-specific cleanup operations. */
545 if (cur_ops->cleanup != NULL)
546 cur_ops->cleanup();
548 torture_cleanup_end();
552 * Return the number if non-negative. If -1, the number of CPUs.
553 * If less than -1, that much less than the number of CPUs, but
554 * at least one.
556 static int compute_real(int n)
558 int nr;
560 if (n >= 0) {
561 nr = n;
562 } else {
563 nr = num_online_cpus() + 1 + n;
564 if (nr <= 0)
565 nr = 1;
567 return nr;
571 * RCU perf shutdown kthread. Just waits to be awakened, then shuts
572 * down system.
574 static int
575 rcu_perf_shutdown(void *arg)
577 do {
578 wait_event(shutdown_wq,
579 atomic_read(&n_rcu_perf_writer_finished) >=
580 nrealwriters);
581 } while (atomic_read(&n_rcu_perf_writer_finished) < nrealwriters);
582 smp_mb(); /* Wake before output. */
583 rcu_perf_cleanup();
584 kernel_power_off();
585 return -EINVAL;
589 * kfree_rcu() performance tests: Start a kfree_rcu() loop on all CPUs for number
590 * of iterations and measure total time and number of GP for all iterations to complete.
593 torture_param(int, kfree_nthreads, -1, "Number of threads running loops of kfree_rcu().");
594 torture_param(int, kfree_alloc_num, 8000, "Number of allocations and frees done in an iteration.");
595 torture_param(int, kfree_loops, 10, "Number of loops doing kfree_alloc_num allocations and frees.");
597 static struct task_struct **kfree_reader_tasks;
598 static int kfree_nrealthreads;
599 static atomic_t n_kfree_perf_thread_started;
600 static atomic_t n_kfree_perf_thread_ended;
602 struct kfree_obj {
603 char kfree_obj[8];
604 struct rcu_head rh;
607 static int
608 kfree_perf_thread(void *arg)
610 int i, loop = 0;
611 long me = (long)arg;
612 struct kfree_obj *alloc_ptr;
613 u64 start_time, end_time;
615 VERBOSE_PERFOUT_STRING("kfree_perf_thread task started");
616 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
617 set_user_nice(current, MAX_NICE);
619 start_time = ktime_get_mono_fast_ns();
621 if (atomic_inc_return(&n_kfree_perf_thread_started) >= kfree_nrealthreads) {
622 if (gp_exp)
623 b_rcu_gp_test_started = cur_ops->exp_completed() / 2;
624 else
625 b_rcu_gp_test_started = cur_ops->get_gp_seq();
628 do {
629 for (i = 0; i < kfree_alloc_num; i++) {
630 alloc_ptr = kmalloc(sizeof(struct kfree_obj), GFP_KERNEL);
631 if (!alloc_ptr)
632 return -ENOMEM;
634 kfree_rcu(alloc_ptr, rh);
637 cond_resched();
638 } while (!torture_must_stop() && ++loop < kfree_loops);
640 if (atomic_inc_return(&n_kfree_perf_thread_ended) >= kfree_nrealthreads) {
641 end_time = ktime_get_mono_fast_ns();
643 if (gp_exp)
644 b_rcu_gp_test_finished = cur_ops->exp_completed() / 2;
645 else
646 b_rcu_gp_test_finished = cur_ops->get_gp_seq();
648 pr_alert("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld\n",
649 (unsigned long long)(end_time - start_time), kfree_loops,
650 rcuperf_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started));
651 if (shutdown) {
652 smp_mb(); /* Assign before wake. */
653 wake_up(&shutdown_wq);
657 torture_kthread_stopping("kfree_perf_thread");
658 return 0;
661 static void
662 kfree_perf_cleanup(void)
664 int i;
666 if (torture_cleanup_begin())
667 return;
669 if (kfree_reader_tasks) {
670 for (i = 0; i < kfree_nrealthreads; i++)
671 torture_stop_kthread(kfree_perf_thread,
672 kfree_reader_tasks[i]);
673 kfree(kfree_reader_tasks);
676 torture_cleanup_end();
680 * shutdown kthread. Just waits to be awakened, then shuts down system.
682 static int
683 kfree_perf_shutdown(void *arg)
685 do {
686 wait_event(shutdown_wq,
687 atomic_read(&n_kfree_perf_thread_ended) >=
688 kfree_nrealthreads);
689 } while (atomic_read(&n_kfree_perf_thread_ended) < kfree_nrealthreads);
691 smp_mb(); /* Wake before output. */
693 kfree_perf_cleanup();
694 kernel_power_off();
695 return -EINVAL;
698 static int __init
699 kfree_perf_init(void)
701 long i;
702 int firsterr = 0;
704 kfree_nrealthreads = compute_real(kfree_nthreads);
705 /* Start up the kthreads. */
706 if (shutdown) {
707 init_waitqueue_head(&shutdown_wq);
708 firsterr = torture_create_kthread(kfree_perf_shutdown, NULL,
709 shutdown_task);
710 if (firsterr)
711 goto unwind;
712 schedule_timeout_uninterruptible(1);
715 kfree_reader_tasks = kcalloc(kfree_nrealthreads, sizeof(kfree_reader_tasks[0]),
716 GFP_KERNEL);
717 if (kfree_reader_tasks == NULL) {
718 firsterr = -ENOMEM;
719 goto unwind;
722 for (i = 0; i < kfree_nrealthreads; i++) {
723 firsterr = torture_create_kthread(kfree_perf_thread, (void *)i,
724 kfree_reader_tasks[i]);
725 if (firsterr)
726 goto unwind;
729 while (atomic_read(&n_kfree_perf_thread_started) < kfree_nrealthreads)
730 schedule_timeout_uninterruptible(1);
732 torture_init_end();
733 return 0;
735 unwind:
736 torture_init_end();
737 kfree_perf_cleanup();
738 return firsterr;
741 static int __init
742 rcu_perf_init(void)
744 long i;
745 int firsterr = 0;
746 static struct rcu_perf_ops *perf_ops[] = {
747 &rcu_ops, &srcu_ops, &srcud_ops, &tasks_ops,
750 if (!torture_init_begin(perf_type, verbose))
751 return -EBUSY;
753 /* Process args and tell the world that the perf'er is on the job. */
754 for (i = 0; i < ARRAY_SIZE(perf_ops); i++) {
755 cur_ops = perf_ops[i];
756 if (strcmp(perf_type, cur_ops->name) == 0)
757 break;
759 if (i == ARRAY_SIZE(perf_ops)) {
760 pr_alert("rcu-perf: invalid perf type: \"%s\"\n", perf_type);
761 pr_alert("rcu-perf types:");
762 for (i = 0; i < ARRAY_SIZE(perf_ops); i++)
763 pr_cont(" %s", perf_ops[i]->name);
764 pr_cont("\n");
765 WARN_ON(!IS_MODULE(CONFIG_RCU_PERF_TEST));
766 firsterr = -EINVAL;
767 cur_ops = NULL;
768 goto unwind;
770 if (cur_ops->init)
771 cur_ops->init();
773 if (kfree_rcu_test)
774 return kfree_perf_init();
776 nrealwriters = compute_real(nwriters);
777 nrealreaders = compute_real(nreaders);
778 atomic_set(&n_rcu_perf_reader_started, 0);
779 atomic_set(&n_rcu_perf_writer_started, 0);
780 atomic_set(&n_rcu_perf_writer_finished, 0);
781 rcu_perf_print_module_parms(cur_ops, "Start of test");
783 /* Start up the kthreads. */
785 if (shutdown) {
786 init_waitqueue_head(&shutdown_wq);
787 firsterr = torture_create_kthread(rcu_perf_shutdown, NULL,
788 shutdown_task);
789 if (firsterr)
790 goto unwind;
791 schedule_timeout_uninterruptible(1);
793 reader_tasks = kcalloc(nrealreaders, sizeof(reader_tasks[0]),
794 GFP_KERNEL);
795 if (reader_tasks == NULL) {
796 VERBOSE_PERFOUT_ERRSTRING("out of memory");
797 firsterr = -ENOMEM;
798 goto unwind;
800 for (i = 0; i < nrealreaders; i++) {
801 firsterr = torture_create_kthread(rcu_perf_reader, (void *)i,
802 reader_tasks[i]);
803 if (firsterr)
804 goto unwind;
806 while (atomic_read(&n_rcu_perf_reader_started) < nrealreaders)
807 schedule_timeout_uninterruptible(1);
808 writer_tasks = kcalloc(nrealwriters, sizeof(reader_tasks[0]),
809 GFP_KERNEL);
810 writer_durations = kcalloc(nrealwriters, sizeof(*writer_durations),
811 GFP_KERNEL);
812 writer_n_durations =
813 kcalloc(nrealwriters, sizeof(*writer_n_durations),
814 GFP_KERNEL);
815 if (!writer_tasks || !writer_durations || !writer_n_durations) {
816 VERBOSE_PERFOUT_ERRSTRING("out of memory");
817 firsterr = -ENOMEM;
818 goto unwind;
820 for (i = 0; i < nrealwriters; i++) {
821 writer_durations[i] =
822 kcalloc(MAX_MEAS, sizeof(*writer_durations[i]),
823 GFP_KERNEL);
824 if (!writer_durations[i]) {
825 firsterr = -ENOMEM;
826 goto unwind;
828 firsterr = torture_create_kthread(rcu_perf_writer, (void *)i,
829 writer_tasks[i]);
830 if (firsterr)
831 goto unwind;
833 torture_init_end();
834 return 0;
836 unwind:
837 torture_init_end();
838 rcu_perf_cleanup();
839 return firsterr;
842 module_init(rcu_perf_init);
843 module_exit(rcu_perf_cleanup);