]> git.ipfire.org Git - thirdparty/linux.git/blame - kernel/rcu/rcuperf.c
Merge tag 'x86-boot-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git...
[thirdparty/linux.git] / kernel / rcu / rcuperf.c
CommitLineData
8bf05ed3 1// SPDX-License-Identifier: GPL-2.0+
8704baab
PM
2/*
3 * Read-Copy Update module-based performance-test facility
4 *
8704baab
PM
5 * Copyright (C) IBM Corporation, 2015
6 *
8bf05ed3 7 * Authors: Paul E. McKenney <paulmck@linux.ibm.com>
8704baab 8 */
60500037
PM
9
10#define pr_fmt(fmt) fmt
11
8704baab
PM
12#include <linux/types.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
12af6603 15#include <linux/mm.h>
8704baab
PM
16#include <linux/module.h>
17#include <linux/kthread.h>
18#include <linux/err.h>
19#include <linux/spinlock.h>
20#include <linux/smp.h>
21#include <linux/rcupdate.h>
22#include <linux/interrupt.h>
23#include <linux/sched.h>
ae7e81c0 24#include <uapi/linux/sched/types.h>
8704baab
PM
25#include <linux/atomic.h>
26#include <linux/bitops.h>
27#include <linux/completion.h>
28#include <linux/moduleparam.h>
29#include <linux/percpu.h>
30#include <linux/notifier.h>
31#include <linux/reboot.h>
32#include <linux/freezer.h>
33#include <linux/cpu.h>
34#include <linux/delay.h>
35#include <linux/stat.h>
36#include <linux/srcu.h>
37#include <linux/slab.h>
38#include <asm/byteorder.h>
39#include <linux/torture.h>
40#include <linux/vmalloc.h>
41
25c36329
PM
42#include "rcu.h"
43
8704baab 44MODULE_LICENSE("GPL");
8bf05ed3 45MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
8704baab
PM
46
47#define PERF_FLAG "-perf:"
48#define PERFOUT_STRING(s) \
a56fefa2 49 pr_alert("%s" PERF_FLAG " %s\n", perf_type, s)
8704baab
PM
50#define VERBOSE_PERFOUT_STRING(s) \
51 do { if (verbose) pr_alert("%s" PERF_FLAG " %s\n", perf_type, s); } while (0)
52#define VERBOSE_PERFOUT_ERRSTRING(s) \
53 do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } while (0)
54
85ba6bfe
PM
55/*
56 * The intended use cases for the nreaders and nwriters module parameters
57 * are as follows:
58 *
59 * 1. Specify only the nr_cpus kernel boot parameter. This will
60 * set both nreaders and nwriters to the value specified by
61 * nr_cpus for a mixed reader/writer test.
62 *
63 * 2. Specify the nr_cpus kernel boot parameter, but set
64 * rcuperf.nreaders to zero. This will set nwriters to the
65 * value specified by nr_cpus for an update-only test.
66 *
67 * 3. Specify the nr_cpus kernel boot parameter, but set
68 * rcuperf.nwriters to zero. This will set nreaders to the
69 * value specified by nr_cpus for a read-only test.
70 *
71 * Various other use cases may of course be specified.
72 */
73
e838a7d6
PM
74#ifdef MODULE
75# define RCUPERF_SHUTDOWN 0
76#else
77# define RCUPERF_SHUTDOWN 1
78#endif
79
881ed593
PM
80torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives");
81torture_param(int, gp_async_max, 1000, "Max # outstanding waits per reader");
af06d4f7 82torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
df37e66b 83torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
85ba6bfe 84torture_param(int, nreaders, -1, "Number of RCU reader threads");
8704baab 85torture_param(int, nwriters, -1, "Number of RCU updater threads");
e838a7d6 86torture_param(bool, shutdown, RCUPERF_SHUTDOWN,
492b95e5 87 "Shutdown at end of performance tests.");
90127d60 88torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
820687a7 89torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");
e6e78b00 90torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() perf test?");
f87dc808 91torture_param(int, kfree_mult, 1, "Multiple of kfree_obj size to allocate.");
8704baab
PM
92
93static char *perf_type = "rcu";
94module_param(perf_type, charp, 0444);
b3f3886c 95MODULE_PARM_DESC(perf_type, "Type of RCU to performance-test (rcu, srcu, ...)");
8704baab
PM
96
97static int nrealreaders;
98static int nrealwriters;
99static struct task_struct **writer_tasks;
100static struct task_struct **reader_tasks;
101static struct task_struct *shutdown_task;
102
103static u64 **writer_durations;
104static int *writer_n_durations;
105static atomic_t n_rcu_perf_reader_started;
106static atomic_t n_rcu_perf_writer_started;
107static atomic_t n_rcu_perf_writer_finished;
108static wait_queue_head_t shutdown_wq;
109static u64 t_rcu_perf_writer_started;
110static u64 t_rcu_perf_writer_finished;
e6e78b00
JFG
111static unsigned long b_rcu_gp_test_started;
112static unsigned long b_rcu_gp_test_finished;
881ed593 113static DEFINE_PER_CPU(atomic_t, n_async_inflight);
8704baab 114
8704baab
PM
115#define MAX_MEAS 10000
116#define MIN_MEAS 100
117
8704baab
PM
118/*
119 * Operations vector for selecting different types of tests.
120 */
121
122struct rcu_perf_ops {
123 int ptype;
124 void (*init)(void);
125 void (*cleanup)(void);
126 int (*readlock)(void);
127 void (*readunlock)(int idx);
17ef2fe9 128 unsigned long (*get_gp_seq)(void);
d7219312 129 unsigned long (*gp_diff)(unsigned long new, unsigned long old);
8704baab 130 unsigned long (*exp_completed)(void);
881ed593
PM
131 void (*async)(struct rcu_head *head, rcu_callback_t func);
132 void (*gp_barrier)(void);
8704baab
PM
133 void (*sync)(void);
134 void (*exp_sync)(void);
135 const char *name;
136};
137
138static struct rcu_perf_ops *cur_ops;
139
140/*
141 * Definitions for rcu perf testing.
142 */
143
144static int rcu_perf_read_lock(void) __acquires(RCU)
145{
146 rcu_read_lock();
147 return 0;
148}
149
150static void rcu_perf_read_unlock(int idx) __releases(RCU)
151{
152 rcu_read_unlock();
153}
154
155static unsigned long __maybe_unused rcu_no_completed(void)
156{
157 return 0;
158}
159
160static void rcu_sync_perf_init(void)
161{
162}
163
164static struct rcu_perf_ops rcu_ops = {
165 .ptype = RCU_FLAVOR,
166 .init = rcu_sync_perf_init,
167 .readlock = rcu_perf_read_lock,
168 .readunlock = rcu_perf_read_unlock,
17ef2fe9 169 .get_gp_seq = rcu_get_gp_seq,
d7219312 170 .gp_diff = rcu_seq_diff,
8704baab 171 .exp_completed = rcu_exp_batches_completed,
881ed593
PM
172 .async = call_rcu,
173 .gp_barrier = rcu_barrier,
8704baab
PM
174 .sync = synchronize_rcu,
175 .exp_sync = synchronize_rcu_expedited,
176 .name = "rcu"
177};
178
8704baab
PM
179/*
180 * Definitions for srcu perf testing.
181 */
182
183DEFINE_STATIC_SRCU(srcu_ctl_perf);
184static struct srcu_struct *srcu_ctlp = &srcu_ctl_perf;
185
186static int srcu_perf_read_lock(void) __acquires(srcu_ctlp)
187{
188 return srcu_read_lock(srcu_ctlp);
189}
190
191static void srcu_perf_read_unlock(int idx) __releases(srcu_ctlp)
192{
193 srcu_read_unlock(srcu_ctlp, idx);
194}
195
196static unsigned long srcu_perf_completed(void)
197{
198 return srcu_batches_completed(srcu_ctlp);
199}
200
881ed593
PM
201static void srcu_call_rcu(struct rcu_head *head, rcu_callback_t func)
202{
203 call_srcu(srcu_ctlp, head, func);
204}
205
206static void srcu_rcu_barrier(void)
207{
208 srcu_barrier(srcu_ctlp);
209}
210
8704baab
PM
211static void srcu_perf_synchronize(void)
212{
213 synchronize_srcu(srcu_ctlp);
214}
215
216static void srcu_perf_synchronize_expedited(void)
217{
218 synchronize_srcu_expedited(srcu_ctlp);
219}
220
221static struct rcu_perf_ops srcu_ops = {
222 .ptype = SRCU_FLAVOR,
223 .init = rcu_sync_perf_init,
224 .readlock = srcu_perf_read_lock,
225 .readunlock = srcu_perf_read_unlock,
17ef2fe9 226 .get_gp_seq = srcu_perf_completed,
d7219312 227 .gp_diff = rcu_seq_diff,
8704baab 228 .exp_completed = srcu_perf_completed,
881ed593
PM
229 .async = srcu_call_rcu,
230 .gp_barrier = srcu_rcu_barrier,
8704baab
PM
231 .sync = srcu_perf_synchronize,
232 .exp_sync = srcu_perf_synchronize_expedited,
233 .name = "srcu"
234};
235
f60cb4d4
PM
236static struct srcu_struct srcud;
237
238static void srcu_sync_perf_init(void)
239{
240 srcu_ctlp = &srcud;
241 init_srcu_struct(srcu_ctlp);
242}
243
244static void srcu_sync_perf_cleanup(void)
245{
246 cleanup_srcu_struct(srcu_ctlp);
247}
248
249static struct rcu_perf_ops srcud_ops = {
250 .ptype = SRCU_FLAVOR,
251 .init = srcu_sync_perf_init,
252 .cleanup = srcu_sync_perf_cleanup,
253 .readlock = srcu_perf_read_lock,
254 .readunlock = srcu_perf_read_unlock,
17ef2fe9 255 .get_gp_seq = srcu_perf_completed,
d7219312 256 .gp_diff = rcu_seq_diff,
f60cb4d4
PM
257 .exp_completed = srcu_perf_completed,
258 .async = srcu_call_rcu,
259 .gp_barrier = srcu_rcu_barrier,
260 .sync = srcu_perf_synchronize,
261 .exp_sync = srcu_perf_synchronize_expedited,
262 .name = "srcud"
263};
264
8704baab
PM
265/*
266 * Definitions for RCU-tasks perf testing.
267 */
268
269static int tasks_perf_read_lock(void)
270{
271 return 0;
272}
273
274static void tasks_perf_read_unlock(int idx)
275{
276}
277
278static struct rcu_perf_ops tasks_ops = {
279 .ptype = RCU_TASKS_FLAVOR,
280 .init = rcu_sync_perf_init,
281 .readlock = tasks_perf_read_lock,
282 .readunlock = tasks_perf_read_unlock,
17ef2fe9 283 .get_gp_seq = rcu_no_completed,
d7219312 284 .gp_diff = rcu_seq_diff,
881ed593
PM
285 .async = call_rcu_tasks,
286 .gp_barrier = rcu_barrier_tasks,
8704baab
PM
287 .sync = synchronize_rcu_tasks,
288 .exp_sync = synchronize_rcu_tasks,
289 .name = "tasks"
290};
291
d7219312
PM
292static unsigned long rcuperf_seq_diff(unsigned long new, unsigned long old)
293{
294 if (!cur_ops->gp_diff)
295 return new - old;
296 return cur_ops->gp_diff(new, old);
297}
298
8704baab
PM
299/*
300 * If performance tests complete, wait for shutdown to commence.
301 */
302static void rcu_perf_wait_shutdown(void)
303{
cee43939 304 cond_resched_tasks_rcu_qs();
8704baab
PM
305 if (atomic_read(&n_rcu_perf_writer_finished) < nrealwriters)
306 return;
307 while (!torture_must_stop())
308 schedule_timeout_uninterruptible(1);
309}
310
311/*
312 * RCU perf reader kthread. Repeatedly does empty RCU read-side
313 * critical section, minimizing update-side interference.
314 */
315static int
316rcu_perf_reader(void *arg)
317{
318 unsigned long flags;
319 int idx;
6b558c4c 320 long me = (long)arg;
8704baab
PM
321
322 VERBOSE_PERFOUT_STRING("rcu_perf_reader task started");
6b558c4c 323 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
8704baab
PM
324 set_user_nice(current, MAX_NICE);
325 atomic_inc(&n_rcu_perf_reader_started);
326
327 do {
328 local_irq_save(flags);
329 idx = cur_ops->readlock();
330 cur_ops->readunlock(idx);
331 local_irq_restore(flags);
332 rcu_perf_wait_shutdown();
333 } while (!torture_must_stop());
334 torture_kthread_stopping("rcu_perf_reader");
335 return 0;
336}
337
881ed593
PM
338/*
339 * Callback function for asynchronous grace periods from rcu_perf_writer().
340 */
341static void rcu_perf_async_cb(struct rcu_head *rhp)
342{
343 atomic_dec(this_cpu_ptr(&n_async_inflight));
344 kfree(rhp);
345}
346
8704baab
PM
347/*
348 * RCU perf writer kthread. Repeatedly does a grace period.
349 */
350static int
351rcu_perf_writer(void *arg)
352{
353 int i = 0;
354 int i_max;
355 long me = (long)arg;
881ed593 356 struct rcu_head *rhp = NULL;
2094c995 357 struct sched_param sp;
8704baab
PM
358 bool started = false, done = false, alldone = false;
359 u64 t;
360 u64 *wdp;
361 u64 *wdpp = writer_durations[me];
362
363 VERBOSE_PERFOUT_STRING("rcu_perf_writer task started");
8704baab 364 WARN_ON(!wdpp);
6b558c4c 365 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
2094c995
PM
366 sp.sched_priority = 1;
367 sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
df37e66b
PM
368
369 if (holdoff)
370 schedule_timeout_uninterruptible(holdoff * HZ);
371
77e9752c
JFG
372 /*
373 * Wait until rcu_end_inkernel_boot() is called for normal GP tests
374 * so that RCU is not always expedited for normal GP tests.
375 * The system_state test is approximate, but works well in practice.
376 */
377 while (!gp_exp && system_state != SYSTEM_RUNNING)
378 schedule_timeout_uninterruptible(1);
379
8704baab
PM
380 t = ktime_get_mono_fast_ns();
381 if (atomic_inc_return(&n_rcu_perf_writer_started) >= nrealwriters) {
382 t_rcu_perf_writer_started = t;
383 if (gp_exp) {
e6e78b00 384 b_rcu_gp_test_started =
8704baab
PM
385 cur_ops->exp_completed() / 2;
386 } else {
e6e78b00 387 b_rcu_gp_test_started = cur_ops->get_gp_seq();
8704baab
PM
388 }
389 }
390
391 do {
820687a7
PM
392 if (writer_holdoff)
393 udelay(writer_holdoff);
8704baab
PM
394 wdp = &wdpp[i];
395 *wdp = ktime_get_mono_fast_ns();
881ed593
PM
396 if (gp_async) {
397retry:
398 if (!rhp)
399 rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
400 if (rhp && atomic_read(this_cpu_ptr(&n_async_inflight)) < gp_async_max) {
881ed593
PM
401 atomic_inc(this_cpu_ptr(&n_async_inflight));
402 cur_ops->async(rhp, rcu_perf_async_cb);
403 rhp = NULL;
404 } else if (!kthread_should_stop()) {
881ed593
PM
405 cur_ops->gp_barrier();
406 goto retry;
407 } else {
408 kfree(rhp); /* Because we are stopping. */
409 }
410 } else if (gp_exp) {
8704baab
PM
411 cur_ops->exp_sync();
412 } else {
8704baab
PM
413 cur_ops->sync();
414 }
8704baab
PM
415 t = ktime_get_mono_fast_ns();
416 *wdp = t - *wdp;
417 i_max = i;
418 if (!started &&
419 atomic_read(&n_rcu_perf_writer_started) >= nrealwriters)
420 started = true;
421 if (!done && i >= MIN_MEAS) {
422 done = true;
620316e5
PM
423 sp.sched_priority = 0;
424 sched_setscheduler_nocheck(current,
425 SCHED_NORMAL, &sp);
a56fefa2
SP
426 pr_alert("%s%s rcu_perf_writer %ld has %d measurements\n",
427 perf_type, PERF_FLAG, me, MIN_MEAS);
8704baab
PM
428 if (atomic_inc_return(&n_rcu_perf_writer_finished) >=
429 nrealwriters) {
620316e5 430 schedule_timeout_interruptible(10);
ac2bb275 431 rcu_ftrace_dump(DUMP_ALL);
8704baab
PM
432 PERFOUT_STRING("Test complete");
433 t_rcu_perf_writer_finished = t;
434 if (gp_exp) {
e6e78b00 435 b_rcu_gp_test_finished =
8704baab
PM
436 cur_ops->exp_completed() / 2;
437 } else {
e6e78b00 438 b_rcu_gp_test_finished =
17ef2fe9 439 cur_ops->get_gp_seq();
8704baab 440 }
e6fb1fc1
AS
441 if (shutdown) {
442 smp_mb(); /* Assign before wake. */
443 wake_up(&shutdown_wq);
444 }
8704baab
PM
445 }
446 }
447 if (done && !alldone &&
448 atomic_read(&n_rcu_perf_writer_finished) >= nrealwriters)
449 alldone = true;
450 if (started && !alldone && i < MAX_MEAS - 1)
451 i++;
452 rcu_perf_wait_shutdown();
453 } while (!torture_must_stop());
881ed593 454 if (gp_async) {
881ed593
PM
455 cur_ops->gp_barrier();
456 }
8704baab
PM
457 writer_n_durations[me] = i_max;
458 torture_kthread_stopping("rcu_perf_writer");
459 return 0;
460}
461
96221795 462static void
8704baab
PM
463rcu_perf_print_module_parms(struct rcu_perf_ops *cur_ops, const char *tag)
464{
465 pr_alert("%s" PERF_FLAG
466 "--- %s: nreaders=%d nwriters=%d verbose=%d shutdown=%d\n",
467 perf_type, tag, nrealreaders, nrealwriters, verbose, shutdown);
468}
469
470static void
471rcu_perf_cleanup(void)
472{
473 int i;
474 int j;
475 int ngps = 0;
476 u64 *wdp;
477 u64 *wdpp;
478
9683937d
PM
479 /*
480 * Would like warning at start, but everything is expedited
481 * during the mid-boot phase, so have to wait till the end.
482 */
483 if (rcu_gp_is_expedited() && !rcu_gp_is_normal() && !gp_exp)
484 VERBOSE_PERFOUT_ERRSTRING("All grace periods expedited, no normal ones to measure!");
485 if (rcu_gp_is_normal() && gp_exp)
486 VERBOSE_PERFOUT_ERRSTRING("All grace periods normal, no expedited ones to measure!");
881ed593
PM
487 if (gp_exp && gp_async)
488 VERBOSE_PERFOUT_ERRSTRING("No expedited async GPs, so went with async!");
9683937d 489
8704baab
PM
490 if (torture_cleanup_begin())
491 return;
ad092c02
PM
492 if (!cur_ops) {
493 torture_cleanup_end();
494 return;
495 }
8704baab
PM
496
497 if (reader_tasks) {
498 for (i = 0; i < nrealreaders; i++)
499 torture_stop_kthread(rcu_perf_reader,
500 reader_tasks[i]);
501 kfree(reader_tasks);
502 }
503
504 if (writer_tasks) {
505 for (i = 0; i < nrealwriters; i++) {
506 torture_stop_kthread(rcu_perf_writer,
507 writer_tasks[i]);
508 if (!writer_n_durations)
509 continue;
510 j = writer_n_durations[i];
511 pr_alert("%s%s writer %d gps: %d\n",
512 perf_type, PERF_FLAG, i, j);
513 ngps += j;
514 }
515 pr_alert("%s%s start: %llu end: %llu duration: %llu gps: %d batches: %ld\n",
516 perf_type, PERF_FLAG,
517 t_rcu_perf_writer_started, t_rcu_perf_writer_finished,
518 t_rcu_perf_writer_finished -
519 t_rcu_perf_writer_started,
520 ngps,
e6e78b00
JFG
521 rcuperf_seq_diff(b_rcu_gp_test_finished,
522 b_rcu_gp_test_started));
8704baab
PM
523 for (i = 0; i < nrealwriters; i++) {
524 if (!writer_durations)
525 break;
526 if (!writer_n_durations)
527 continue;
528 wdpp = writer_durations[i];
529 if (!wdpp)
530 continue;
531 for (j = 0; j <= writer_n_durations[i]; j++) {
532 wdp = &wdpp[j];
533 pr_alert("%s%s %4d writer-duration: %5d %llu\n",
534 perf_type, PERF_FLAG,
535 i, j, *wdp);
536 if (j % 100 == 0)
537 schedule_timeout_uninterruptible(1);
538 }
539 kfree(writer_durations[i]);
540 }
541 kfree(writer_tasks);
542 kfree(writer_durations);
543 kfree(writer_n_durations);
544 }
545
620d2460 546 /* Do torture-type-specific cleanup operations. */
8704baab
PM
547 if (cur_ops->cleanup != NULL)
548 cur_ops->cleanup();
549
550 torture_cleanup_end();
551}
552
553/*
554 * Return the number if non-negative. If -1, the number of CPUs.
555 * If less than -1, that much less than the number of CPUs, but
556 * at least one.
557 */
558static int compute_real(int n)
559{
560 int nr;
561
562 if (n >= 0) {
563 nr = n;
564 } else {
565 nr = num_online_cpus() + 1 + n;
566 if (nr <= 0)
567 nr = 1;
568 }
569 return nr;
570}
571
572/*
573 * RCU perf shutdown kthread. Just waits to be awakened, then shuts
574 * down system.
575 */
576static int
577rcu_perf_shutdown(void *arg)
578{
579 do {
580 wait_event(shutdown_wq,
581 atomic_read(&n_rcu_perf_writer_finished) >=
582 nrealwriters);
583 } while (atomic_read(&n_rcu_perf_writer_finished) < nrealwriters);
584 smp_mb(); /* Wake before output. */
585 rcu_perf_cleanup();
586 kernel_power_off();
587 return -EINVAL;
588}
589
e6e78b00
JFG
590/*
591 * kfree_rcu() performance tests: Start a kfree_rcu() loop on all CPUs for number
592 * of iterations and measure total time and number of GP for all iterations to complete.
593 */
594
595torture_param(int, kfree_nthreads, -1, "Number of threads running loops of kfree_rcu().");
596torture_param(int, kfree_alloc_num, 8000, "Number of allocations and frees done in an iteration.");
597torture_param(int, kfree_loops, 10, "Number of loops doing kfree_alloc_num allocations and frees.");
e6e78b00
JFG
598
599static struct task_struct **kfree_reader_tasks;
600static int kfree_nrealthreads;
601static atomic_t n_kfree_perf_thread_started;
602static atomic_t n_kfree_perf_thread_ended;
603
604struct kfree_obj {
605 char kfree_obj[8];
606 struct rcu_head rh;
607};
608
609static int
610kfree_perf_thread(void *arg)
611{
612 int i, loop = 0;
613 long me = (long)arg;
614 struct kfree_obj *alloc_ptr;
615 u64 start_time, end_time;
12af6603 616 long long mem_begin, mem_during = 0;
e6e78b00
JFG
617
618 VERBOSE_PERFOUT_STRING("kfree_perf_thread task started");
619 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
620 set_user_nice(current, MAX_NICE);
621
622 start_time = ktime_get_mono_fast_ns();
623
624 if (atomic_inc_return(&n_kfree_perf_thread_started) >= kfree_nrealthreads) {
625 if (gp_exp)
626 b_rcu_gp_test_started = cur_ops->exp_completed() / 2;
627 else
628 b_rcu_gp_test_started = cur_ops->get_gp_seq();
629 }
630
631 do {
12af6603
JFG
632 if (!mem_during) {
633 mem_during = mem_begin = si_mem_available();
634 } else if (loop % (kfree_loops / 4) == 0) {
635 mem_during = (mem_during + si_mem_available()) / 2;
636 }
637
e6e78b00 638 for (i = 0; i < kfree_alloc_num; i++) {
f87dc808 639 alloc_ptr = kmalloc(kfree_mult * sizeof(struct kfree_obj), GFP_KERNEL);
e6e78b00
JFG
640 if (!alloc_ptr)
641 return -ENOMEM;
642
189a6883 643 kfree_rcu(alloc_ptr, rh);
e6e78b00
JFG
644 }
645
646 cond_resched();
647 } while (!torture_must_stop() && ++loop < kfree_loops);
648
649 if (atomic_inc_return(&n_kfree_perf_thread_ended) >= kfree_nrealthreads) {
650 end_time = ktime_get_mono_fast_ns();
651
652 if (gp_exp)
653 b_rcu_gp_test_finished = cur_ops->exp_completed() / 2;
654 else
655 b_rcu_gp_test_finished = cur_ops->get_gp_seq();
656
12af6603 657 pr_alert("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld, memory footprint: %lldMB\n",
e6e78b00 658 (unsigned long long)(end_time - start_time), kfree_loops,
12af6603
JFG
659 rcuperf_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started),
660 (mem_begin - mem_during) >> (20 - PAGE_SHIFT));
661
e6e78b00
JFG
662 if (shutdown) {
663 smp_mb(); /* Assign before wake. */
664 wake_up(&shutdown_wq);
665 }
666 }
667
668 torture_kthread_stopping("kfree_perf_thread");
669 return 0;
670}
671
672static void
673kfree_perf_cleanup(void)
674{
675 int i;
676
677 if (torture_cleanup_begin())
678 return;
679
680 if (kfree_reader_tasks) {
681 for (i = 0; i < kfree_nrealthreads; i++)
682 torture_stop_kthread(kfree_perf_thread,
683 kfree_reader_tasks[i]);
684 kfree(kfree_reader_tasks);
685 }
686
687 torture_cleanup_end();
688}
689
690/*
691 * shutdown kthread. Just waits to be awakened, then shuts down system.
692 */
693static int
694kfree_perf_shutdown(void *arg)
695{
696 do {
697 wait_event(shutdown_wq,
698 atomic_read(&n_kfree_perf_thread_ended) >=
699 kfree_nrealthreads);
700 } while (atomic_read(&n_kfree_perf_thread_ended) < kfree_nrealthreads);
701
702 smp_mb(); /* Wake before output. */
703
704 kfree_perf_cleanup();
705 kernel_power_off();
706 return -EINVAL;
707}
708
709static int __init
710kfree_perf_init(void)
711{
712 long i;
713 int firsterr = 0;
714
715 kfree_nrealthreads = compute_real(kfree_nthreads);
716 /* Start up the kthreads. */
717 if (shutdown) {
718 init_waitqueue_head(&shutdown_wq);
719 firsterr = torture_create_kthread(kfree_perf_shutdown, NULL,
720 shutdown_task);
721 if (firsterr)
722 goto unwind;
723 schedule_timeout_uninterruptible(1);
724 }
725
f87dc808
JFG
726 pr_alert("kfree object size=%lu\n", kfree_mult * sizeof(struct kfree_obj));
727
e6e78b00
JFG
728 kfree_reader_tasks = kcalloc(kfree_nrealthreads, sizeof(kfree_reader_tasks[0]),
729 GFP_KERNEL);
730 if (kfree_reader_tasks == NULL) {
731 firsterr = -ENOMEM;
732 goto unwind;
733 }
734
735 for (i = 0; i < kfree_nrealthreads; i++) {
736 firsterr = torture_create_kthread(kfree_perf_thread, (void *)i,
737 kfree_reader_tasks[i]);
738 if (firsterr)
739 goto unwind;
740 }
741
742 while (atomic_read(&n_kfree_perf_thread_started) < kfree_nrealthreads)
743 schedule_timeout_uninterruptible(1);
744
745 torture_init_end();
746 return 0;
747
748unwind:
749 torture_init_end();
750 kfree_perf_cleanup();
751 return firsterr;
752}
753
8704baab
PM
754static int __init
755rcu_perf_init(void)
756{
757 long i;
758 int firsterr = 0;
759 static struct rcu_perf_ops *perf_ops[] = {
620d2460 760 &rcu_ops, &srcu_ops, &srcud_ops, &tasks_ops,
8704baab
PM
761 };
762
a2f2577d 763 if (!torture_init_begin(perf_type, verbose))
8704baab
PM
764 return -EBUSY;
765
766 /* Process args and tell the world that the perf'er is on the job. */
767 for (i = 0; i < ARRAY_SIZE(perf_ops); i++) {
768 cur_ops = perf_ops[i];
769 if (strcmp(perf_type, cur_ops->name) == 0)
770 break;
771 }
772 if (i == ARRAY_SIZE(perf_ops)) {
a7538352 773 pr_alert("rcu-perf: invalid perf type: \"%s\"\n", perf_type);
8704baab
PM
774 pr_alert("rcu-perf types:");
775 for (i = 0; i < ARRAY_SIZE(perf_ops); i++)
a7538352
JP
776 pr_cont(" %s", perf_ops[i]->name);
777 pr_cont("\n");
f0288064 778 WARN_ON(!IS_MODULE(CONFIG_RCU_PERF_TEST));
8704baab 779 firsterr = -EINVAL;
ad092c02 780 cur_ops = NULL;
8704baab
PM
781 goto unwind;
782 }
783 if (cur_ops->init)
784 cur_ops->init();
785
e6e78b00
JFG
786 if (kfree_rcu_test)
787 return kfree_perf_init();
788
8704baab
PM
789 nrealwriters = compute_real(nwriters);
790 nrealreaders = compute_real(nreaders);
791 atomic_set(&n_rcu_perf_reader_started, 0);
792 atomic_set(&n_rcu_perf_writer_started, 0);
793 atomic_set(&n_rcu_perf_writer_finished, 0);
794 rcu_perf_print_module_parms(cur_ops, "Start of test");
795
796 /* Start up the kthreads. */
797
798 if (shutdown) {
799 init_waitqueue_head(&shutdown_wq);
800 firsterr = torture_create_kthread(rcu_perf_shutdown, NULL,
801 shutdown_task);
802 if (firsterr)
803 goto unwind;
804 schedule_timeout_uninterruptible(1);
805 }
806 reader_tasks = kcalloc(nrealreaders, sizeof(reader_tasks[0]),
807 GFP_KERNEL);
808 if (reader_tasks == NULL) {
809 VERBOSE_PERFOUT_ERRSTRING("out of memory");
810 firsterr = -ENOMEM;
811 goto unwind;
812 }
813 for (i = 0; i < nrealreaders; i++) {
6b558c4c 814 firsterr = torture_create_kthread(rcu_perf_reader, (void *)i,
8704baab
PM
815 reader_tasks[i]);
816 if (firsterr)
817 goto unwind;
818 }
819 while (atomic_read(&n_rcu_perf_reader_started) < nrealreaders)
820 schedule_timeout_uninterruptible(1);
821 writer_tasks = kcalloc(nrealwriters, sizeof(reader_tasks[0]),
822 GFP_KERNEL);
823 writer_durations = kcalloc(nrealwriters, sizeof(*writer_durations),
824 GFP_KERNEL);
825 writer_n_durations =
826 kcalloc(nrealwriters, sizeof(*writer_n_durations),
827 GFP_KERNEL);
828 if (!writer_tasks || !writer_durations || !writer_n_durations) {
829 VERBOSE_PERFOUT_ERRSTRING("out of memory");
830 firsterr = -ENOMEM;
831 goto unwind;
832 }
833 for (i = 0; i < nrealwriters; i++) {
834 writer_durations[i] =
835 kcalloc(MAX_MEAS, sizeof(*writer_durations[i]),
836 GFP_KERNEL);
05dbbfe7
WY
837 if (!writer_durations[i]) {
838 firsterr = -ENOMEM;
8704baab 839 goto unwind;
05dbbfe7 840 }
8704baab
PM
841 firsterr = torture_create_kthread(rcu_perf_writer, (void *)i,
842 writer_tasks[i]);
843 if (firsterr)
844 goto unwind;
845 }
846 torture_init_end();
847 return 0;
848
849unwind:
850 torture_init_end();
851 rcu_perf_cleanup();
852 return firsterr;
853}
854
855module_init(rcu_perf_init);
856module_exit(rcu_perf_cleanup);