11fbeb3a8SPaul E. McKenney // SPDX-License-Identifier: GPL-2.0+
21fbeb3a8SPaul E. McKenney //
31fbeb3a8SPaul E. McKenney // Scalability test comparing RCU vs other mechanisms
41fbeb3a8SPaul E. McKenney // for acquiring references on objects.
51fbeb3a8SPaul E. McKenney //
61fbeb3a8SPaul E. McKenney // Copyright (C) Google, 2020.
71fbeb3a8SPaul E. McKenney //
81fbeb3a8SPaul E. McKenney // Author: Joel Fernandes <[email protected]>
91fbeb3a8SPaul E. McKenney
101fbeb3a8SPaul E. McKenney #define pr_fmt(fmt) fmt
111fbeb3a8SPaul E. McKenney
121fbeb3a8SPaul E. McKenney #include <linux/atomic.h>
131fbeb3a8SPaul E. McKenney #include <linux/bitops.h>
141fbeb3a8SPaul E. McKenney #include <linux/completion.h>
151fbeb3a8SPaul E. McKenney #include <linux/cpu.h>
161fbeb3a8SPaul E. McKenney #include <linux/delay.h>
171fbeb3a8SPaul E. McKenney #include <linux/err.h>
181fbeb3a8SPaul E. McKenney #include <linux/init.h>
191fbeb3a8SPaul E. McKenney #include <linux/interrupt.h>
201fbeb3a8SPaul E. McKenney #include <linux/kthread.h>
211fbeb3a8SPaul E. McKenney #include <linux/kernel.h>
221fbeb3a8SPaul E. McKenney #include <linux/mm.h>
231fbeb3a8SPaul E. McKenney #include <linux/module.h>
241fbeb3a8SPaul E. McKenney #include <linux/moduleparam.h>
251fbeb3a8SPaul E. McKenney #include <linux/notifier.h>
261fbeb3a8SPaul E. McKenney #include <linux/percpu.h>
271fbeb3a8SPaul E. McKenney #include <linux/rcupdate.h>
281fbeb3a8SPaul E. McKenney #include <linux/rcupdate_trace.h>
291fbeb3a8SPaul E. McKenney #include <linux/reboot.h>
301fbeb3a8SPaul E. McKenney #include <linux/sched.h>
314e39bb49SChristophe JAILLET #include <linux/seq_buf.h>
321fbeb3a8SPaul E. McKenney #include <linux/spinlock.h>
331fbeb3a8SPaul E. McKenney #include <linux/smp.h>
341fbeb3a8SPaul E. McKenney #include <linux/stat.h>
351fbeb3a8SPaul E. McKenney #include <linux/srcu.h>
361fbeb3a8SPaul E. McKenney #include <linux/slab.h>
371fbeb3a8SPaul E. McKenney #include <linux/torture.h>
381fbeb3a8SPaul E. McKenney #include <linux/types.h>
391806b1f9SPaul E. McKenney #include <linux/sched/clock.h>
401fbeb3a8SPaul E. McKenney
411fbeb3a8SPaul E. McKenney #include "rcu.h"
421fbeb3a8SPaul E. McKenney
431fbeb3a8SPaul E. McKenney #define SCALE_FLAG "-ref-scale: "
441fbeb3a8SPaul E. McKenney
451fbeb3a8SPaul E. McKenney #define SCALEOUT(s, x...) \
461fbeb3a8SPaul E. McKenney pr_alert("%s" SCALE_FLAG s, scale_type, ## x)
471fbeb3a8SPaul E. McKenney
481fbeb3a8SPaul E. McKenney #define VERBOSE_SCALEOUT(s, x...) \
49f71f22b6SLi Zhijian do { \
50f71f22b6SLi Zhijian if (verbose) \
51f71f22b6SLi Zhijian pr_alert("%s" SCALE_FLAG s "\n", scale_type, ## x); \
52f71f22b6SLi Zhijian } while (0)
531fbeb3a8SPaul E. McKenney
54e76506f0SPaul E. McKenney static atomic_t verbose_batch_ctr;
55e76506f0SPaul E. McKenney
56e76506f0SPaul E. McKenney #define VERBOSE_SCALEOUT_BATCH(s, x...) \
57e76506f0SPaul E. McKenney do { \
58e76506f0SPaul E. McKenney if (verbose && \
59e76506f0SPaul E. McKenney (verbose_batched <= 0 || \
60414c116eSPaul E. McKenney !(atomic_inc_return(&verbose_batch_ctr) % verbose_batched))) { \
61414c116eSPaul E. McKenney schedule_timeout_uninterruptible(1); \
62f71f22b6SLi Zhijian pr_alert("%s" SCALE_FLAG s "\n", scale_type, ## x); \
63414c116eSPaul E. McKenney } \
64e76506f0SPaul E. McKenney } while (0)
65e76506f0SPaul E. McKenney
66f71f22b6SLi Zhijian #define SCALEOUT_ERRSTRING(s, x...) pr_alert("%s" SCALE_FLAG "!!! " s "\n", scale_type, ## x)
671fbeb3a8SPaul E. McKenney
68b9f147cdSJeff Johnson MODULE_DESCRIPTION("Scalability test for object reference mechanisms");
691fbeb3a8SPaul E. McKenney MODULE_LICENSE("GPL");
701fbeb3a8SPaul E. McKenney MODULE_AUTHOR("Joel Fernandes (Google) <[email protected]>");
711fbeb3a8SPaul E. McKenney
721fbeb3a8SPaul E. McKenney static char *scale_type = "rcu";
731fbeb3a8SPaul E. McKenney module_param(scale_type, charp, 0444);
741fbeb3a8SPaul E. McKenney MODULE_PARM_DESC(scale_type, "Type of test (rcu, srcu, refcnt, rwsem, rwlock.");
751fbeb3a8SPaul E. McKenney
761fbeb3a8SPaul E. McKenney torture_param(int, verbose, 0, "Enable verbose debugging printk()s");
77e76506f0SPaul E. McKenney torture_param(int, verbose_batched, 0, "Batch verbose debugging printk()s");
781fbeb3a8SPaul E. McKenney
79ff9ba8dbSPaul E. McKenney // Number of seconds to extend warm-up and cool-down for multiple guest OSes
80ff9ba8dbSPaul E. McKenney torture_param(long, guest_os_delay, 0,
81ff9ba8dbSPaul E. McKenney "Number of seconds to extend warm-up/cool-down for multiple guest OSes.");
821fbeb3a8SPaul E. McKenney // Wait until there are multiple CPUs before starting test.
831fbeb3a8SPaul E. McKenney torture_param(int, holdoff, IS_BUILTIN(CONFIG_RCU_REF_SCALE_TEST) ? 10 : 0,
841fbeb3a8SPaul E. McKenney "Holdoff time before test start (s)");
85a6889becSPaul E. McKenney // Number of typesafe_lookup structures, that is, the degree of concurrency.
86a6889becSPaul E. McKenney torture_param(long, lookup_instances, 0, "Number of typesafe_lookup structures.");
871fbeb3a8SPaul E. McKenney // Number of loops per experiment, all readers execute operations concurrently.
881fbeb3a8SPaul E. McKenney torture_param(long, loops, 10000, "Number of loops per experiment.");
891fbeb3a8SPaul E. McKenney // Number of readers, with -1 defaulting to about 75% of the CPUs.
901fbeb3a8SPaul E. McKenney torture_param(int, nreaders, -1, "Number of readers, -1 for 75% of CPUs.");
911fbeb3a8SPaul E. McKenney // Number of runs.
921fbeb3a8SPaul E. McKenney torture_param(int, nruns, 30, "Number of experiments to run.");
931fbeb3a8SPaul E. McKenney // Reader delay in nanoseconds, 0 for no delay.
941fbeb3a8SPaul E. McKenney torture_param(int, readdelay, 0, "Read-side delay in nanoseconds.");
951fbeb3a8SPaul E. McKenney
961fbeb3a8SPaul E. McKenney #ifdef MODULE
971fbeb3a8SPaul E. McKenney # define REFSCALE_SHUTDOWN 0
981fbeb3a8SPaul E. McKenney #else
991fbeb3a8SPaul E. McKenney # define REFSCALE_SHUTDOWN 1
1001fbeb3a8SPaul E. McKenney #endif
1011fbeb3a8SPaul E. McKenney
1021fbeb3a8SPaul E. McKenney torture_param(bool, shutdown, REFSCALE_SHUTDOWN,
1031fbeb3a8SPaul E. McKenney "Shutdown at end of scalability tests.");
1041fbeb3a8SPaul E. McKenney
1051fbeb3a8SPaul E. McKenney struct reader_task {
1061fbeb3a8SPaul E. McKenney struct task_struct *task;
1071fbeb3a8SPaul E. McKenney int start_reader;
1081fbeb3a8SPaul E. McKenney wait_queue_head_t wq;
1091fbeb3a8SPaul E. McKenney u64 last_duration_ns;
1101fbeb3a8SPaul E. McKenney };
1111fbeb3a8SPaul E. McKenney
1121fbeb3a8SPaul E. McKenney static struct task_struct *shutdown_task;
1131fbeb3a8SPaul E. McKenney static wait_queue_head_t shutdown_wq;
1141fbeb3a8SPaul E. McKenney
1151fbeb3a8SPaul E. McKenney static struct task_struct *main_task;
1161fbeb3a8SPaul E. McKenney static wait_queue_head_t main_wq;
1171fbeb3a8SPaul E. McKenney static int shutdown_start;
1181fbeb3a8SPaul E. McKenney
1191fbeb3a8SPaul E. McKenney static struct reader_task *reader_tasks;
1201fbeb3a8SPaul E. McKenney
1211fbeb3a8SPaul E. McKenney // Number of readers that are part of the current experiment.
1221fbeb3a8SPaul E. McKenney static atomic_t nreaders_exp;
1231fbeb3a8SPaul E. McKenney
1241fbeb3a8SPaul E. McKenney // Use to wait for all threads to start.
1251fbeb3a8SPaul E. McKenney static atomic_t n_init;
1261fbeb3a8SPaul E. McKenney static atomic_t n_started;
1271fbeb3a8SPaul E. McKenney static atomic_t n_warmedup;
1281fbeb3a8SPaul E. McKenney static atomic_t n_cooleddown;
1291fbeb3a8SPaul E. McKenney
1301fbeb3a8SPaul E. McKenney // Track which experiment is currently running.
1311fbeb3a8SPaul E. McKenney static int exp_idx;
1321fbeb3a8SPaul E. McKenney
1331fbeb3a8SPaul E. McKenney // Operations vector for selecting different types of tests.
1341fbeb3a8SPaul E. McKenney struct ref_scale_ops {
1353c6496c8SPaul E. McKenney bool (*init)(void);
1361fbeb3a8SPaul E. McKenney void (*cleanup)(void);
1371fbeb3a8SPaul E. McKenney void (*readsection)(const int nloops);
1381fbeb3a8SPaul E. McKenney void (*delaysection)(const int nloops, const int udl, const int ndl);
1391fbeb3a8SPaul E. McKenney const char *name;
1401fbeb3a8SPaul E. McKenney };
1411fbeb3a8SPaul E. McKenney
1428f35fefaSChristophe JAILLET static const struct ref_scale_ops *cur_ops;
1431fbeb3a8SPaul E. McKenney
un_delay(const int udl,const int ndl)1441fbeb3a8SPaul E. McKenney static void un_delay(const int udl, const int ndl)
1451fbeb3a8SPaul E. McKenney {
1461fbeb3a8SPaul E. McKenney if (udl)
1471fbeb3a8SPaul E. McKenney udelay(udl);
1481fbeb3a8SPaul E. McKenney if (ndl)
1491fbeb3a8SPaul E. McKenney ndelay(ndl);
1501fbeb3a8SPaul E. McKenney }
1511fbeb3a8SPaul E. McKenney
ref_rcu_read_section(const int nloops)1521fbeb3a8SPaul E. McKenney static void ref_rcu_read_section(const int nloops)
1531fbeb3a8SPaul E. McKenney {
1541fbeb3a8SPaul E. McKenney int i;
1551fbeb3a8SPaul E. McKenney
1561fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
1571fbeb3a8SPaul E. McKenney rcu_read_lock();
1581fbeb3a8SPaul E. McKenney rcu_read_unlock();
1591fbeb3a8SPaul E. McKenney }
1601fbeb3a8SPaul E. McKenney }
1611fbeb3a8SPaul E. McKenney
ref_rcu_delay_section(const int nloops,const int udl,const int ndl)1621fbeb3a8SPaul E. McKenney static void ref_rcu_delay_section(const int nloops, const int udl, const int ndl)
1631fbeb3a8SPaul E. McKenney {
1641fbeb3a8SPaul E. McKenney int i;
1651fbeb3a8SPaul E. McKenney
1661fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
1671fbeb3a8SPaul E. McKenney rcu_read_lock();
1681fbeb3a8SPaul E. McKenney un_delay(udl, ndl);
1691fbeb3a8SPaul E. McKenney rcu_read_unlock();
1701fbeb3a8SPaul E. McKenney }
1711fbeb3a8SPaul E. McKenney }
1721fbeb3a8SPaul E. McKenney
rcu_sync_scale_init(void)1733c6496c8SPaul E. McKenney static bool rcu_sync_scale_init(void)
1741fbeb3a8SPaul E. McKenney {
1753c6496c8SPaul E. McKenney return true;
1761fbeb3a8SPaul E. McKenney }
1771fbeb3a8SPaul E. McKenney
1788f35fefaSChristophe JAILLET static const struct ref_scale_ops rcu_ops = {
1791fbeb3a8SPaul E. McKenney .init = rcu_sync_scale_init,
1801fbeb3a8SPaul E. McKenney .readsection = ref_rcu_read_section,
1811fbeb3a8SPaul E. McKenney .delaysection = ref_rcu_delay_section,
1821fbeb3a8SPaul E. McKenney .name = "rcu"
1831fbeb3a8SPaul E. McKenney };
1841fbeb3a8SPaul E. McKenney
1851fbeb3a8SPaul E. McKenney // Definitions for SRCU ref scale testing.
1861fbeb3a8SPaul E. McKenney DEFINE_STATIC_SRCU(srcu_refctl_scale);
1871fbeb3a8SPaul E. McKenney static struct srcu_struct *srcu_ctlp = &srcu_refctl_scale;
1881fbeb3a8SPaul E. McKenney
srcu_ref_scale_read_section(const int nloops)1891fbeb3a8SPaul E. McKenney static void srcu_ref_scale_read_section(const int nloops)
1901fbeb3a8SPaul E. McKenney {
1911fbeb3a8SPaul E. McKenney int i;
1921fbeb3a8SPaul E. McKenney int idx;
1931fbeb3a8SPaul E. McKenney
1941fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
1951fbeb3a8SPaul E. McKenney idx = srcu_read_lock(srcu_ctlp);
1961fbeb3a8SPaul E. McKenney srcu_read_unlock(srcu_ctlp, idx);
1971fbeb3a8SPaul E. McKenney }
1981fbeb3a8SPaul E. McKenney }
1991fbeb3a8SPaul E. McKenney
srcu_ref_scale_delay_section(const int nloops,const int udl,const int ndl)2001fbeb3a8SPaul E. McKenney static void srcu_ref_scale_delay_section(const int nloops, const int udl, const int ndl)
2011fbeb3a8SPaul E. McKenney {
2021fbeb3a8SPaul E. McKenney int i;
2031fbeb3a8SPaul E. McKenney int idx;
2041fbeb3a8SPaul E. McKenney
2051fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
2061fbeb3a8SPaul E. McKenney idx = srcu_read_lock(srcu_ctlp);
2071fbeb3a8SPaul E. McKenney un_delay(udl, ndl);
2081fbeb3a8SPaul E. McKenney srcu_read_unlock(srcu_ctlp, idx);
2091fbeb3a8SPaul E. McKenney }
2101fbeb3a8SPaul E. McKenney }
2111fbeb3a8SPaul E. McKenney
2128f35fefaSChristophe JAILLET static const struct ref_scale_ops srcu_ops = {
2131fbeb3a8SPaul E. McKenney .init = rcu_sync_scale_init,
2141fbeb3a8SPaul E. McKenney .readsection = srcu_ref_scale_read_section,
2151fbeb3a8SPaul E. McKenney .delaysection = srcu_ref_scale_delay_section,
2161fbeb3a8SPaul E. McKenney .name = "srcu"
2171fbeb3a8SPaul E. McKenney };
2181fbeb3a8SPaul E. McKenney
srcu_fast_ref_scale_read_section(const int nloops)219*4c3fca0fSPaul E. McKenney static void srcu_fast_ref_scale_read_section(const int nloops)
220*4c3fca0fSPaul E. McKenney {
221*4c3fca0fSPaul E. McKenney int i;
222*4c3fca0fSPaul E. McKenney struct srcu_ctr __percpu *scp;
223*4c3fca0fSPaul E. McKenney
224*4c3fca0fSPaul E. McKenney for (i = nloops; i >= 0; i--) {
225*4c3fca0fSPaul E. McKenney scp = srcu_read_lock_fast(srcu_ctlp);
226*4c3fca0fSPaul E. McKenney srcu_read_unlock_fast(srcu_ctlp, scp);
227*4c3fca0fSPaul E. McKenney }
228*4c3fca0fSPaul E. McKenney }
229*4c3fca0fSPaul E. McKenney
srcu_fast_ref_scale_delay_section(const int nloops,const int udl,const int ndl)230*4c3fca0fSPaul E. McKenney static void srcu_fast_ref_scale_delay_section(const int nloops, const int udl, const int ndl)
231*4c3fca0fSPaul E. McKenney {
232*4c3fca0fSPaul E. McKenney int i;
233*4c3fca0fSPaul E. McKenney struct srcu_ctr __percpu *scp;
234*4c3fca0fSPaul E. McKenney
235*4c3fca0fSPaul E. McKenney for (i = nloops; i >= 0; i--) {
236*4c3fca0fSPaul E. McKenney scp = srcu_read_lock_fast(srcu_ctlp);
237*4c3fca0fSPaul E. McKenney un_delay(udl, ndl);
238*4c3fca0fSPaul E. McKenney srcu_read_unlock_fast(srcu_ctlp, scp);
239*4c3fca0fSPaul E. McKenney }
240*4c3fca0fSPaul E. McKenney }
241*4c3fca0fSPaul E. McKenney
242*4c3fca0fSPaul E. McKenney static const struct ref_scale_ops srcu_fast_ops = {
243*4c3fca0fSPaul E. McKenney .init = rcu_sync_scale_init,
244*4c3fca0fSPaul E. McKenney .readsection = srcu_fast_ref_scale_read_section,
245*4c3fca0fSPaul E. McKenney .delaysection = srcu_fast_ref_scale_delay_section,
246*4c3fca0fSPaul E. McKenney .name = "srcu-fast"
247*4c3fca0fSPaul E. McKenney };
248*4c3fca0fSPaul E. McKenney
srcu_lite_ref_scale_read_section(const int nloops)2496a2c0255SPaul E. McKenney static void srcu_lite_ref_scale_read_section(const int nloops)
2506a2c0255SPaul E. McKenney {
2516a2c0255SPaul E. McKenney int i;
2526a2c0255SPaul E. McKenney int idx;
2536a2c0255SPaul E. McKenney
2546a2c0255SPaul E. McKenney for (i = nloops; i >= 0; i--) {
2556a2c0255SPaul E. McKenney idx = srcu_read_lock_lite(srcu_ctlp);
2566a2c0255SPaul E. McKenney srcu_read_unlock_lite(srcu_ctlp, idx);
2576a2c0255SPaul E. McKenney }
2586a2c0255SPaul E. McKenney }
2596a2c0255SPaul E. McKenney
srcu_lite_ref_scale_delay_section(const int nloops,const int udl,const int ndl)2606a2c0255SPaul E. McKenney static void srcu_lite_ref_scale_delay_section(const int nloops, const int udl, const int ndl)
2616a2c0255SPaul E. McKenney {
2626a2c0255SPaul E. McKenney int i;
2636a2c0255SPaul E. McKenney int idx;
2646a2c0255SPaul E. McKenney
2656a2c0255SPaul E. McKenney for (i = nloops; i >= 0; i--) {
2666a2c0255SPaul E. McKenney idx = srcu_read_lock_lite(srcu_ctlp);
2676a2c0255SPaul E. McKenney un_delay(udl, ndl);
2686a2c0255SPaul E. McKenney srcu_read_unlock_lite(srcu_ctlp, idx);
2696a2c0255SPaul E. McKenney }
2706a2c0255SPaul E. McKenney }
2716a2c0255SPaul E. McKenney
2726a2c0255SPaul E. McKenney static const struct ref_scale_ops srcu_lite_ops = {
2736a2c0255SPaul E. McKenney .init = rcu_sync_scale_init,
2746a2c0255SPaul E. McKenney .readsection = srcu_lite_ref_scale_read_section,
2756a2c0255SPaul E. McKenney .delaysection = srcu_lite_ref_scale_delay_section,
2766a2c0255SPaul E. McKenney .name = "srcu-lite"
2776a2c0255SPaul E. McKenney };
2786a2c0255SPaul E. McKenney
2795f654af1SPaul E. McKenney #ifdef CONFIG_TASKS_RCU
2805f654af1SPaul E. McKenney
2811fbeb3a8SPaul E. McKenney // Definitions for RCU Tasks ref scale testing: Empty read markers.
2821fbeb3a8SPaul E. McKenney // These definitions also work for RCU Rude readers.
rcu_tasks_ref_scale_read_section(const int nloops)2831fbeb3a8SPaul E. McKenney static void rcu_tasks_ref_scale_read_section(const int nloops)
2841fbeb3a8SPaul E. McKenney {
2851fbeb3a8SPaul E. McKenney int i;
2861fbeb3a8SPaul E. McKenney
2871fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--)
2881fbeb3a8SPaul E. McKenney continue;
2891fbeb3a8SPaul E. McKenney }
2901fbeb3a8SPaul E. McKenney
rcu_tasks_ref_scale_delay_section(const int nloops,const int udl,const int ndl)2911fbeb3a8SPaul E. McKenney static void rcu_tasks_ref_scale_delay_section(const int nloops, const int udl, const int ndl)
2921fbeb3a8SPaul E. McKenney {
2931fbeb3a8SPaul E. McKenney int i;
2941fbeb3a8SPaul E. McKenney
2951fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--)
2961fbeb3a8SPaul E. McKenney un_delay(udl, ndl);
2971fbeb3a8SPaul E. McKenney }
2981fbeb3a8SPaul E. McKenney
2998f35fefaSChristophe JAILLET static const struct ref_scale_ops rcu_tasks_ops = {
3001fbeb3a8SPaul E. McKenney .init = rcu_sync_scale_init,
3011fbeb3a8SPaul E. McKenney .readsection = rcu_tasks_ref_scale_read_section,
3021fbeb3a8SPaul E. McKenney .delaysection = rcu_tasks_ref_scale_delay_section,
3031fbeb3a8SPaul E. McKenney .name = "rcu-tasks"
3041fbeb3a8SPaul E. McKenney };
3051fbeb3a8SPaul E. McKenney
3065f654af1SPaul E. McKenney #define RCU_TASKS_OPS &rcu_tasks_ops,
3075f654af1SPaul E. McKenney
3085f654af1SPaul E. McKenney #else // #ifdef CONFIG_TASKS_RCU
3095f654af1SPaul E. McKenney
3105f654af1SPaul E. McKenney #define RCU_TASKS_OPS
3115f654af1SPaul E. McKenney
3125f654af1SPaul E. McKenney #endif // #else // #ifdef CONFIG_TASKS_RCU
3135f654af1SPaul E. McKenney
314dec86781SPaul E. McKenney #ifdef CONFIG_TASKS_TRACE_RCU
315dec86781SPaul E. McKenney
3161fbeb3a8SPaul E. McKenney // Definitions for RCU Tasks Trace ref scale testing.
rcu_trace_ref_scale_read_section(const int nloops)3171fbeb3a8SPaul E. McKenney static void rcu_trace_ref_scale_read_section(const int nloops)
3181fbeb3a8SPaul E. McKenney {
3191fbeb3a8SPaul E. McKenney int i;
3201fbeb3a8SPaul E. McKenney
3211fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
3221fbeb3a8SPaul E. McKenney rcu_read_lock_trace();
3231fbeb3a8SPaul E. McKenney rcu_read_unlock_trace();
3241fbeb3a8SPaul E. McKenney }
3251fbeb3a8SPaul E. McKenney }
3261fbeb3a8SPaul E. McKenney
rcu_trace_ref_scale_delay_section(const int nloops,const int udl,const int ndl)3271fbeb3a8SPaul E. McKenney static void rcu_trace_ref_scale_delay_section(const int nloops, const int udl, const int ndl)
3281fbeb3a8SPaul E. McKenney {
3291fbeb3a8SPaul E. McKenney int i;
3301fbeb3a8SPaul E. McKenney
3311fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
3321fbeb3a8SPaul E. McKenney rcu_read_lock_trace();
3331fbeb3a8SPaul E. McKenney un_delay(udl, ndl);
3341fbeb3a8SPaul E. McKenney rcu_read_unlock_trace();
3351fbeb3a8SPaul E. McKenney }
3361fbeb3a8SPaul E. McKenney }
3371fbeb3a8SPaul E. McKenney
3388f35fefaSChristophe JAILLET static const struct ref_scale_ops rcu_trace_ops = {
3391fbeb3a8SPaul E. McKenney .init = rcu_sync_scale_init,
3401fbeb3a8SPaul E. McKenney .readsection = rcu_trace_ref_scale_read_section,
3411fbeb3a8SPaul E. McKenney .delaysection = rcu_trace_ref_scale_delay_section,
3421fbeb3a8SPaul E. McKenney .name = "rcu-trace"
3431fbeb3a8SPaul E. McKenney };
3441fbeb3a8SPaul E. McKenney
345dec86781SPaul E. McKenney #define RCU_TRACE_OPS &rcu_trace_ops,
346dec86781SPaul E. McKenney
347dec86781SPaul E. McKenney #else // #ifdef CONFIG_TASKS_TRACE_RCU
348dec86781SPaul E. McKenney
349dec86781SPaul E. McKenney #define RCU_TRACE_OPS
350dec86781SPaul E. McKenney
351dec86781SPaul E. McKenney #endif // #else // #ifdef CONFIG_TASKS_TRACE_RCU
352dec86781SPaul E. McKenney
3531fbeb3a8SPaul E. McKenney // Definitions for reference count
3541fbeb3a8SPaul E. McKenney static atomic_t refcnt;
3551fbeb3a8SPaul E. McKenney
ref_refcnt_section(const int nloops)3561fbeb3a8SPaul E. McKenney static void ref_refcnt_section(const int nloops)
3571fbeb3a8SPaul E. McKenney {
3581fbeb3a8SPaul E. McKenney int i;
3591fbeb3a8SPaul E. McKenney
3601fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
3611fbeb3a8SPaul E. McKenney atomic_inc(&refcnt);
3621fbeb3a8SPaul E. McKenney atomic_dec(&refcnt);
3631fbeb3a8SPaul E. McKenney }
3641fbeb3a8SPaul E. McKenney }
3651fbeb3a8SPaul E. McKenney
ref_refcnt_delay_section(const int nloops,const int udl,const int ndl)3661fbeb3a8SPaul E. McKenney static void ref_refcnt_delay_section(const int nloops, const int udl, const int ndl)
3671fbeb3a8SPaul E. McKenney {
3681fbeb3a8SPaul E. McKenney int i;
3691fbeb3a8SPaul E. McKenney
3701fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
3711fbeb3a8SPaul E. McKenney atomic_inc(&refcnt);
3721fbeb3a8SPaul E. McKenney un_delay(udl, ndl);
3731fbeb3a8SPaul E. McKenney atomic_dec(&refcnt);
3741fbeb3a8SPaul E. McKenney }
3751fbeb3a8SPaul E. McKenney }
3761fbeb3a8SPaul E. McKenney
3778f35fefaSChristophe JAILLET static const struct ref_scale_ops refcnt_ops = {
3781fbeb3a8SPaul E. McKenney .init = rcu_sync_scale_init,
3791fbeb3a8SPaul E. McKenney .readsection = ref_refcnt_section,
3801fbeb3a8SPaul E. McKenney .delaysection = ref_refcnt_delay_section,
3811fbeb3a8SPaul E. McKenney .name = "refcnt"
3821fbeb3a8SPaul E. McKenney };
3831fbeb3a8SPaul E. McKenney
3841fbeb3a8SPaul E. McKenney // Definitions for rwlock
3851fbeb3a8SPaul E. McKenney static rwlock_t test_rwlock;
3861fbeb3a8SPaul E. McKenney
ref_rwlock_init(void)3873c6496c8SPaul E. McKenney static bool ref_rwlock_init(void)
3881fbeb3a8SPaul E. McKenney {
3891fbeb3a8SPaul E. McKenney rwlock_init(&test_rwlock);
3903c6496c8SPaul E. McKenney return true;
3911fbeb3a8SPaul E. McKenney }
3921fbeb3a8SPaul E. McKenney
ref_rwlock_section(const int nloops)3931fbeb3a8SPaul E. McKenney static void ref_rwlock_section(const int nloops)
3941fbeb3a8SPaul E. McKenney {
3951fbeb3a8SPaul E. McKenney int i;
3961fbeb3a8SPaul E. McKenney
3971fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
3981fbeb3a8SPaul E. McKenney read_lock(&test_rwlock);
3991fbeb3a8SPaul E. McKenney read_unlock(&test_rwlock);
4001fbeb3a8SPaul E. McKenney }
4011fbeb3a8SPaul E. McKenney }
4021fbeb3a8SPaul E. McKenney
ref_rwlock_delay_section(const int nloops,const int udl,const int ndl)4031fbeb3a8SPaul E. McKenney static void ref_rwlock_delay_section(const int nloops, const int udl, const int ndl)
4041fbeb3a8SPaul E. McKenney {
4051fbeb3a8SPaul E. McKenney int i;
4061fbeb3a8SPaul E. McKenney
4071fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
4081fbeb3a8SPaul E. McKenney read_lock(&test_rwlock);
4091fbeb3a8SPaul E. McKenney un_delay(udl, ndl);
4101fbeb3a8SPaul E. McKenney read_unlock(&test_rwlock);
4111fbeb3a8SPaul E. McKenney }
4121fbeb3a8SPaul E. McKenney }
4131fbeb3a8SPaul E. McKenney
4148f35fefaSChristophe JAILLET static const struct ref_scale_ops rwlock_ops = {
4151fbeb3a8SPaul E. McKenney .init = ref_rwlock_init,
4161fbeb3a8SPaul E. McKenney .readsection = ref_rwlock_section,
4171fbeb3a8SPaul E. McKenney .delaysection = ref_rwlock_delay_section,
4181fbeb3a8SPaul E. McKenney .name = "rwlock"
4191fbeb3a8SPaul E. McKenney };
4201fbeb3a8SPaul E. McKenney
4211fbeb3a8SPaul E. McKenney // Definitions for rwsem
4221fbeb3a8SPaul E. McKenney static struct rw_semaphore test_rwsem;
4231fbeb3a8SPaul E. McKenney
ref_rwsem_init(void)4243c6496c8SPaul E. McKenney static bool ref_rwsem_init(void)
4251fbeb3a8SPaul E. McKenney {
4261fbeb3a8SPaul E. McKenney init_rwsem(&test_rwsem);
4273c6496c8SPaul E. McKenney return true;
4281fbeb3a8SPaul E. McKenney }
4291fbeb3a8SPaul E. McKenney
ref_rwsem_section(const int nloops)4301fbeb3a8SPaul E. McKenney static void ref_rwsem_section(const int nloops)
4311fbeb3a8SPaul E. McKenney {
4321fbeb3a8SPaul E. McKenney int i;
4331fbeb3a8SPaul E. McKenney
4341fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
4351fbeb3a8SPaul E. McKenney down_read(&test_rwsem);
4361fbeb3a8SPaul E. McKenney up_read(&test_rwsem);
4371fbeb3a8SPaul E. McKenney }
4381fbeb3a8SPaul E. McKenney }
4391fbeb3a8SPaul E. McKenney
ref_rwsem_delay_section(const int nloops,const int udl,const int ndl)4401fbeb3a8SPaul E. McKenney static void ref_rwsem_delay_section(const int nloops, const int udl, const int ndl)
4411fbeb3a8SPaul E. McKenney {
4421fbeb3a8SPaul E. McKenney int i;
4431fbeb3a8SPaul E. McKenney
4441fbeb3a8SPaul E. McKenney for (i = nloops; i >= 0; i--) {
4451fbeb3a8SPaul E. McKenney down_read(&test_rwsem);
4461fbeb3a8SPaul E. McKenney un_delay(udl, ndl);
4471fbeb3a8SPaul E. McKenney up_read(&test_rwsem);
4481fbeb3a8SPaul E. McKenney }
4491fbeb3a8SPaul E. McKenney }
4501fbeb3a8SPaul E. McKenney
4518f35fefaSChristophe JAILLET static const struct ref_scale_ops rwsem_ops = {
4521fbeb3a8SPaul E. McKenney .init = ref_rwsem_init,
4531fbeb3a8SPaul E. McKenney .readsection = ref_rwsem_section,
4541fbeb3a8SPaul E. McKenney .delaysection = ref_rwsem_delay_section,
4551fbeb3a8SPaul E. McKenney .name = "rwsem"
4561fbeb3a8SPaul E. McKenney };
4571fbeb3a8SPaul E. McKenney
458e9b800dbSPaul E. McKenney // Definitions for global spinlock
4597bf336fbSZqiang static DEFINE_RAW_SPINLOCK(test_lock);
460e9b800dbSPaul E. McKenney
ref_lock_section(const int nloops)461e9b800dbSPaul E. McKenney static void ref_lock_section(const int nloops)
462e9b800dbSPaul E. McKenney {
463e9b800dbSPaul E. McKenney int i;
464e9b800dbSPaul E. McKenney
465e9b800dbSPaul E. McKenney preempt_disable();
466e9b800dbSPaul E. McKenney for (i = nloops; i >= 0; i--) {
4677bf336fbSZqiang raw_spin_lock(&test_lock);
4687bf336fbSZqiang raw_spin_unlock(&test_lock);
469e9b800dbSPaul E. McKenney }
470e9b800dbSPaul E. McKenney preempt_enable();
471e9b800dbSPaul E. McKenney }
472e9b800dbSPaul E. McKenney
ref_lock_delay_section(const int nloops,const int udl,const int ndl)473e9b800dbSPaul E. McKenney static void ref_lock_delay_section(const int nloops, const int udl, const int ndl)
474e9b800dbSPaul E. McKenney {
475e9b800dbSPaul E. McKenney int i;
476e9b800dbSPaul E. McKenney
477e9b800dbSPaul E. McKenney preempt_disable();
478e9b800dbSPaul E. McKenney for (i = nloops; i >= 0; i--) {
4797bf336fbSZqiang raw_spin_lock(&test_lock);
480e9b800dbSPaul E. McKenney un_delay(udl, ndl);
4817bf336fbSZqiang raw_spin_unlock(&test_lock);
482e9b800dbSPaul E. McKenney }
483e9b800dbSPaul E. McKenney preempt_enable();
484e9b800dbSPaul E. McKenney }
485e9b800dbSPaul E. McKenney
4868f35fefaSChristophe JAILLET static const struct ref_scale_ops lock_ops = {
487e9b800dbSPaul E. McKenney .readsection = ref_lock_section,
488e9b800dbSPaul E. McKenney .delaysection = ref_lock_delay_section,
489e9b800dbSPaul E. McKenney .name = "lock"
490e9b800dbSPaul E. McKenney };
491e9b800dbSPaul E. McKenney
492e9b800dbSPaul E. McKenney // Definitions for global irq-save spinlock
493e9b800dbSPaul E. McKenney
ref_lock_irq_section(const int nloops)494e9b800dbSPaul E. McKenney static void ref_lock_irq_section(const int nloops)
495e9b800dbSPaul E. McKenney {
496e9b800dbSPaul E. McKenney unsigned long flags;
497e9b800dbSPaul E. McKenney int i;
498e9b800dbSPaul E. McKenney
499e9b800dbSPaul E. McKenney preempt_disable();
500e9b800dbSPaul E. McKenney for (i = nloops; i >= 0; i--) {
5017bf336fbSZqiang raw_spin_lock_irqsave(&test_lock, flags);
5027bf336fbSZqiang raw_spin_unlock_irqrestore(&test_lock, flags);
503e9b800dbSPaul E. McKenney }
504e9b800dbSPaul E. McKenney preempt_enable();
505e9b800dbSPaul E. McKenney }
506e9b800dbSPaul E. McKenney
ref_lock_irq_delay_section(const int nloops,const int udl,const int ndl)507e9b800dbSPaul E. McKenney static void ref_lock_irq_delay_section(const int nloops, const int udl, const int ndl)
508e9b800dbSPaul E. McKenney {
509e9b800dbSPaul E. McKenney unsigned long flags;
510e9b800dbSPaul E. McKenney int i;
511e9b800dbSPaul E. McKenney
512e9b800dbSPaul E. McKenney preempt_disable();
513e9b800dbSPaul E. McKenney for (i = nloops; i >= 0; i--) {
5147bf336fbSZqiang raw_spin_lock_irqsave(&test_lock, flags);
515e9b800dbSPaul E. McKenney un_delay(udl, ndl);
5167bf336fbSZqiang raw_spin_unlock_irqrestore(&test_lock, flags);
517e9b800dbSPaul E. McKenney }
518e9b800dbSPaul E. McKenney preempt_enable();
519e9b800dbSPaul E. McKenney }
520e9b800dbSPaul E. McKenney
5218f35fefaSChristophe JAILLET static const struct ref_scale_ops lock_irq_ops = {
522e9b800dbSPaul E. McKenney .readsection = ref_lock_irq_section,
523e9b800dbSPaul E. McKenney .delaysection = ref_lock_irq_delay_section,
524e9b800dbSPaul E. McKenney .name = "lock-irq"
525e9b800dbSPaul E. McKenney };
526e9b800dbSPaul E. McKenney
527e9b800dbSPaul E. McKenney // Definitions acquire-release.
528e9b800dbSPaul E. McKenney static DEFINE_PER_CPU(unsigned long, test_acqrel);
529e9b800dbSPaul E. McKenney
ref_acqrel_section(const int nloops)530e9b800dbSPaul E. McKenney static void ref_acqrel_section(const int nloops)
531e9b800dbSPaul E. McKenney {
532e9b800dbSPaul E. McKenney unsigned long x;
533e9b800dbSPaul E. McKenney int i;
534e9b800dbSPaul E. McKenney
535e9b800dbSPaul E. McKenney preempt_disable();
536e9b800dbSPaul E. McKenney for (i = nloops; i >= 0; i--) {
537e9b800dbSPaul E. McKenney x = smp_load_acquire(this_cpu_ptr(&test_acqrel));
538e9b800dbSPaul E. McKenney smp_store_release(this_cpu_ptr(&test_acqrel), x + 1);
539e9b800dbSPaul E. McKenney }
540e9b800dbSPaul E. McKenney preempt_enable();
541e9b800dbSPaul E. McKenney }
542e9b800dbSPaul E. McKenney
ref_acqrel_delay_section(const int nloops,const int udl,const int ndl)543e9b800dbSPaul E. McKenney static void ref_acqrel_delay_section(const int nloops, const int udl, const int ndl)
544e9b800dbSPaul E. McKenney {
545e9b800dbSPaul E. McKenney unsigned long x;
546e9b800dbSPaul E. McKenney int i;
547e9b800dbSPaul E. McKenney
548e9b800dbSPaul E. McKenney preempt_disable();
549e9b800dbSPaul E. McKenney for (i = nloops; i >= 0; i--) {
550e9b800dbSPaul E. McKenney x = smp_load_acquire(this_cpu_ptr(&test_acqrel));
551e9b800dbSPaul E. McKenney un_delay(udl, ndl);
552e9b800dbSPaul E. McKenney smp_store_release(this_cpu_ptr(&test_acqrel), x + 1);
553e9b800dbSPaul E. McKenney }
554e9b800dbSPaul E. McKenney preempt_enable();
555e9b800dbSPaul E. McKenney }
556e9b800dbSPaul E. McKenney
5578f35fefaSChristophe JAILLET static const struct ref_scale_ops acqrel_ops = {
558e9b800dbSPaul E. McKenney .readsection = ref_acqrel_section,
559e9b800dbSPaul E. McKenney .delaysection = ref_acqrel_delay_section,
560e9b800dbSPaul E. McKenney .name = "acqrel"
561e9b800dbSPaul E. McKenney };
562e9b800dbSPaul E. McKenney
56325f6fa53SPaul E. McKenney static volatile u64 stopopts;
56425f6fa53SPaul E. McKenney
ref_sched_clock_section(const int nloops)5651806b1f9SPaul E. McKenney static void ref_sched_clock_section(const int nloops)
5661806b1f9SPaul E. McKenney {
5671806b1f9SPaul E. McKenney u64 x = 0;
5681806b1f9SPaul E. McKenney int i;
5691806b1f9SPaul E. McKenney
5701806b1f9SPaul E. McKenney preempt_disable();
5711806b1f9SPaul E. McKenney for (i = nloops; i >= 0; i--)
5721806b1f9SPaul E. McKenney x += sched_clock();
5731806b1f9SPaul E. McKenney preempt_enable();
5741806b1f9SPaul E. McKenney stopopts = x;
5751806b1f9SPaul E. McKenney }
5761806b1f9SPaul E. McKenney
ref_sched_clock_delay_section(const int nloops,const int udl,const int ndl)5771806b1f9SPaul E. McKenney static void ref_sched_clock_delay_section(const int nloops, const int udl, const int ndl)
5781806b1f9SPaul E. McKenney {
5791806b1f9SPaul E. McKenney u64 x = 0;
5801806b1f9SPaul E. McKenney int i;
5811806b1f9SPaul E. McKenney
5821806b1f9SPaul E. McKenney preempt_disable();
5831806b1f9SPaul E. McKenney for (i = nloops; i >= 0; i--) {
5841806b1f9SPaul E. McKenney x += sched_clock();
5851806b1f9SPaul E. McKenney un_delay(udl, ndl);
5861806b1f9SPaul E. McKenney }
5871806b1f9SPaul E. McKenney preempt_enable();
5881806b1f9SPaul E. McKenney stopopts = x;
5891806b1f9SPaul E. McKenney }
5901806b1f9SPaul E. McKenney
5911806b1f9SPaul E. McKenney static const struct ref_scale_ops sched_clock_ops = {
5921806b1f9SPaul E. McKenney .readsection = ref_sched_clock_section,
5931806b1f9SPaul E. McKenney .delaysection = ref_sched_clock_delay_section,
5941806b1f9SPaul E. McKenney .name = "sched-clock"
5951806b1f9SPaul E. McKenney };
5961806b1f9SPaul E. McKenney
5971806b1f9SPaul E. McKenney
ref_clock_section(const int nloops)59825f6fa53SPaul E. McKenney static void ref_clock_section(const int nloops)
59925f6fa53SPaul E. McKenney {
60025f6fa53SPaul E. McKenney u64 x = 0;
60125f6fa53SPaul E. McKenney int i;
60225f6fa53SPaul E. McKenney
60325f6fa53SPaul E. McKenney preempt_disable();
60425f6fa53SPaul E. McKenney for (i = nloops; i >= 0; i--)
60525f6fa53SPaul E. McKenney x += ktime_get_real_fast_ns();
60625f6fa53SPaul E. McKenney preempt_enable();
60725f6fa53SPaul E. McKenney stopopts = x;
60825f6fa53SPaul E. McKenney }
60925f6fa53SPaul E. McKenney
ref_clock_delay_section(const int nloops,const int udl,const int ndl)61025f6fa53SPaul E. McKenney static void ref_clock_delay_section(const int nloops, const int udl, const int ndl)
61125f6fa53SPaul E. McKenney {
61225f6fa53SPaul E. McKenney u64 x = 0;
61325f6fa53SPaul E. McKenney int i;
61425f6fa53SPaul E. McKenney
61525f6fa53SPaul E. McKenney preempt_disable();
61625f6fa53SPaul E. McKenney for (i = nloops; i >= 0; i--) {
61725f6fa53SPaul E. McKenney x += ktime_get_real_fast_ns();
61825f6fa53SPaul E. McKenney un_delay(udl, ndl);
61925f6fa53SPaul E. McKenney }
62025f6fa53SPaul E. McKenney preempt_enable();
62125f6fa53SPaul E. McKenney stopopts = x;
62225f6fa53SPaul E. McKenney }
62325f6fa53SPaul E. McKenney
6248f35fefaSChristophe JAILLET static const struct ref_scale_ops clock_ops = {
62525f6fa53SPaul E. McKenney .readsection = ref_clock_section,
62625f6fa53SPaul E. McKenney .delaysection = ref_clock_delay_section,
62725f6fa53SPaul E. McKenney .name = "clock"
62825f6fa53SPaul E. McKenney };
62925f6fa53SPaul E. McKenney
ref_jiffies_section(const int nloops)630b5a2801fSPaul E. McKenney static void ref_jiffies_section(const int nloops)
631b5a2801fSPaul E. McKenney {
632b5a2801fSPaul E. McKenney u64 x = 0;
633b5a2801fSPaul E. McKenney int i;
634b5a2801fSPaul E. McKenney
635b5a2801fSPaul E. McKenney preempt_disable();
636b5a2801fSPaul E. McKenney for (i = nloops; i >= 0; i--)
637b5a2801fSPaul E. McKenney x += jiffies;
638b5a2801fSPaul E. McKenney preempt_enable();
639b5a2801fSPaul E. McKenney stopopts = x;
640b5a2801fSPaul E. McKenney }
641b5a2801fSPaul E. McKenney
ref_jiffies_delay_section(const int nloops,const int udl,const int ndl)642b5a2801fSPaul E. McKenney static void ref_jiffies_delay_section(const int nloops, const int udl, const int ndl)
643b5a2801fSPaul E. McKenney {
644b5a2801fSPaul E. McKenney u64 x = 0;
645b5a2801fSPaul E. McKenney int i;
646b5a2801fSPaul E. McKenney
647b5a2801fSPaul E. McKenney preempt_disable();
648b5a2801fSPaul E. McKenney for (i = nloops; i >= 0; i--) {
649b5a2801fSPaul E. McKenney x += jiffies;
650b5a2801fSPaul E. McKenney un_delay(udl, ndl);
651b5a2801fSPaul E. McKenney }
652b5a2801fSPaul E. McKenney preempt_enable();
653b5a2801fSPaul E. McKenney stopopts = x;
654b5a2801fSPaul E. McKenney }
655b5a2801fSPaul E. McKenney
6568f35fefaSChristophe JAILLET static const struct ref_scale_ops jiffies_ops = {
657b5a2801fSPaul E. McKenney .readsection = ref_jiffies_section,
658b5a2801fSPaul E. McKenney .delaysection = ref_jiffies_delay_section,
659b5a2801fSPaul E. McKenney .name = "jiffies"
660b5a2801fSPaul E. McKenney };
661b5a2801fSPaul E. McKenney
662a6889becSPaul E. McKenney ////////////////////////////////////////////////////////////////////////
663a6889becSPaul E. McKenney //
664a6889becSPaul E. McKenney // Methods leveraging SLAB_TYPESAFE_BY_RCU.
665a6889becSPaul E. McKenney //
666a6889becSPaul E. McKenney
667a6889becSPaul E. McKenney // Item to look up in a typesafe manner. Array of pointers to these.
668a6889becSPaul E. McKenney struct refscale_typesafe {
669a6889becSPaul E. McKenney atomic_t rts_refctr; // Used by all flavors
670a6889becSPaul E. McKenney spinlock_t rts_lock;
671a6889becSPaul E. McKenney seqlock_t rts_seqlock;
672a6889becSPaul E. McKenney unsigned int a;
673a6889becSPaul E. McKenney unsigned int b;
674a6889becSPaul E. McKenney };
675a6889becSPaul E. McKenney
676a6889becSPaul E. McKenney static struct kmem_cache *typesafe_kmem_cachep;
677a6889becSPaul E. McKenney static struct refscale_typesafe **rtsarray;
678a6889becSPaul E. McKenney static long rtsarray_size;
679a6889becSPaul E. McKenney static DEFINE_TORTURE_RANDOM_PERCPU(refscale_rand);
680a6889becSPaul E. McKenney static bool (*rts_acquire)(struct refscale_typesafe *rtsp, unsigned int *start);
681a6889becSPaul E. McKenney static bool (*rts_release)(struct refscale_typesafe *rtsp, unsigned int start);
682a6889becSPaul E. McKenney
683a6889becSPaul E. McKenney // Conditionally acquire an explicit in-structure reference count.
typesafe_ref_acquire(struct refscale_typesafe * rtsp,unsigned int * start)684a6889becSPaul E. McKenney static bool typesafe_ref_acquire(struct refscale_typesafe *rtsp, unsigned int *start)
685a6889becSPaul E. McKenney {
686a6889becSPaul E. McKenney return atomic_inc_not_zero(&rtsp->rts_refctr);
687a6889becSPaul E. McKenney }
688a6889becSPaul E. McKenney
689a6889becSPaul E. McKenney // Unconditionally release an explicit in-structure reference count.
typesafe_ref_release(struct refscale_typesafe * rtsp,unsigned int start)690a6889becSPaul E. McKenney static bool typesafe_ref_release(struct refscale_typesafe *rtsp, unsigned int start)
691a6889becSPaul E. McKenney {
692a6889becSPaul E. McKenney if (!atomic_dec_return(&rtsp->rts_refctr)) {
693a6889becSPaul E. McKenney WRITE_ONCE(rtsp->a, rtsp->a + 1);
694a6889becSPaul E. McKenney kmem_cache_free(typesafe_kmem_cachep, rtsp);
695a6889becSPaul E. McKenney }
696a6889becSPaul E. McKenney return true;
697a6889becSPaul E. McKenney }
698a6889becSPaul E. McKenney
699a6889becSPaul E. McKenney // Unconditionally acquire an explicit in-structure spinlock.
typesafe_lock_acquire(struct refscale_typesafe * rtsp,unsigned int * start)700a6889becSPaul E. McKenney static bool typesafe_lock_acquire(struct refscale_typesafe *rtsp, unsigned int *start)
701a6889becSPaul E. McKenney {
702a6889becSPaul E. McKenney spin_lock(&rtsp->rts_lock);
703a6889becSPaul E. McKenney return true;
704a6889becSPaul E. McKenney }
705a6889becSPaul E. McKenney
706a6889becSPaul E. McKenney // Unconditionally release an explicit in-structure spinlock.
typesafe_lock_release(struct refscale_typesafe * rtsp,unsigned int start)707a6889becSPaul E. McKenney static bool typesafe_lock_release(struct refscale_typesafe *rtsp, unsigned int start)
708a6889becSPaul E. McKenney {
709a6889becSPaul E. McKenney spin_unlock(&rtsp->rts_lock);
710a6889becSPaul E. McKenney return true;
711a6889becSPaul E. McKenney }
712a6889becSPaul E. McKenney
713a6889becSPaul E. McKenney // Unconditionally acquire an explicit in-structure sequence lock.
typesafe_seqlock_acquire(struct refscale_typesafe * rtsp,unsigned int * start)714a6889becSPaul E. McKenney static bool typesafe_seqlock_acquire(struct refscale_typesafe *rtsp, unsigned int *start)
715a6889becSPaul E. McKenney {
716a6889becSPaul E. McKenney *start = read_seqbegin(&rtsp->rts_seqlock);
717a6889becSPaul E. McKenney return true;
718a6889becSPaul E. McKenney }
719a6889becSPaul E. McKenney
720a6889becSPaul E. McKenney // Conditionally release an explicit in-structure sequence lock. Return
721a6889becSPaul E. McKenney // true if this release was successful, that is, if no retry is required.
typesafe_seqlock_release(struct refscale_typesafe * rtsp,unsigned int start)722a6889becSPaul E. McKenney static bool typesafe_seqlock_release(struct refscale_typesafe *rtsp, unsigned int start)
723a6889becSPaul E. McKenney {
724a6889becSPaul E. McKenney return !read_seqretry(&rtsp->rts_seqlock, start);
725a6889becSPaul E. McKenney }
726a6889becSPaul E. McKenney
727a6889becSPaul E. McKenney // Do a read-side critical section with the specified delay in
728a6889becSPaul E. McKenney // microseconds and nanoseconds inserted so as to increase probability
729a6889becSPaul E. McKenney // of failure.
typesafe_delay_section(const int nloops,const int udl,const int ndl)730a6889becSPaul E. McKenney static void typesafe_delay_section(const int nloops, const int udl, const int ndl)
731a6889becSPaul E. McKenney {
732a6889becSPaul E. McKenney unsigned int a;
733a6889becSPaul E. McKenney unsigned int b;
734a6889becSPaul E. McKenney int i;
735a6889becSPaul E. McKenney long idx;
736a6889becSPaul E. McKenney struct refscale_typesafe *rtsp;
737a6889becSPaul E. McKenney unsigned int start;
738a6889becSPaul E. McKenney
739a6889becSPaul E. McKenney for (i = nloops; i >= 0; i--) {
740a6889becSPaul E. McKenney preempt_disable();
741a6889becSPaul E. McKenney idx = torture_random(this_cpu_ptr(&refscale_rand)) % rtsarray_size;
742a6889becSPaul E. McKenney preempt_enable();
743a6889becSPaul E. McKenney retry:
744a6889becSPaul E. McKenney rcu_read_lock();
745a6889becSPaul E. McKenney rtsp = rcu_dereference(rtsarray[idx]);
746a6889becSPaul E. McKenney a = READ_ONCE(rtsp->a);
747a6889becSPaul E. McKenney if (!rts_acquire(rtsp, &start)) {
748a6889becSPaul E. McKenney rcu_read_unlock();
749a6889becSPaul E. McKenney goto retry;
750a6889becSPaul E. McKenney }
751a6889becSPaul E. McKenney if (a != READ_ONCE(rtsp->a)) {
752a6889becSPaul E. McKenney (void)rts_release(rtsp, start);
753a6889becSPaul E. McKenney rcu_read_unlock();
754a6889becSPaul E. McKenney goto retry;
755a6889becSPaul E. McKenney }
756a6889becSPaul E. McKenney un_delay(udl, ndl);
757730c3ed4SPaul E. McKenney b = READ_ONCE(rtsp->a);
758a6889becSPaul E. McKenney // Remember, seqlock read-side release can fail.
759a6889becSPaul E. McKenney if (!rts_release(rtsp, start)) {
760a6889becSPaul E. McKenney rcu_read_unlock();
761a6889becSPaul E. McKenney goto retry;
762a6889becSPaul E. McKenney }
763a6889becSPaul E. McKenney WARN_ONCE(a != b, "Re-read of ->a changed from %u to %u.\n", a, b);
764a6889becSPaul E. McKenney b = rtsp->b;
765a6889becSPaul E. McKenney rcu_read_unlock();
766a6889becSPaul E. McKenney WARN_ON_ONCE(a * a != b);
767a6889becSPaul E. McKenney }
768a6889becSPaul E. McKenney }
769a6889becSPaul E. McKenney
770a6889becSPaul E. McKenney // Because the acquisition and release methods are expensive, there
771a6889becSPaul E. McKenney // is no point in optimizing away the un_delay() function's two checks.
772a6889becSPaul E. McKenney // Thus simply define typesafe_read_section() as a simple wrapper around
773a6889becSPaul E. McKenney // typesafe_delay_section().
typesafe_read_section(const int nloops)774a6889becSPaul E. McKenney static void typesafe_read_section(const int nloops)
775a6889becSPaul E. McKenney {
776a6889becSPaul E. McKenney typesafe_delay_section(nloops, 0, 0);
777a6889becSPaul E. McKenney }
778a6889becSPaul E. McKenney
779a6889becSPaul E. McKenney // Allocate and initialize one refscale_typesafe structure.
typesafe_alloc_one(void)780a6889becSPaul E. McKenney static struct refscale_typesafe *typesafe_alloc_one(void)
781a6889becSPaul E. McKenney {
782a6889becSPaul E. McKenney struct refscale_typesafe *rtsp;
783a6889becSPaul E. McKenney
784a6889becSPaul E. McKenney rtsp = kmem_cache_alloc(typesafe_kmem_cachep, GFP_KERNEL);
785a6889becSPaul E. McKenney if (!rtsp)
786a6889becSPaul E. McKenney return NULL;
787a6889becSPaul E. McKenney atomic_set(&rtsp->rts_refctr, 1);
788a6889becSPaul E. McKenney WRITE_ONCE(rtsp->a, rtsp->a + 1);
789a6889becSPaul E. McKenney WRITE_ONCE(rtsp->b, rtsp->a * rtsp->a);
790a6889becSPaul E. McKenney return rtsp;
791a6889becSPaul E. McKenney }
792a6889becSPaul E. McKenney
793a6889becSPaul E. McKenney // Slab-allocator constructor for refscale_typesafe structures created
794a6889becSPaul E. McKenney // out of a new slab of system memory.
refscale_typesafe_ctor(void * rtsp_in)795a6889becSPaul E. McKenney static void refscale_typesafe_ctor(void *rtsp_in)
796a6889becSPaul E. McKenney {
797a6889becSPaul E. McKenney struct refscale_typesafe *rtsp = rtsp_in;
798a6889becSPaul E. McKenney
799a6889becSPaul E. McKenney spin_lock_init(&rtsp->rts_lock);
800a6889becSPaul E. McKenney seqlock_init(&rtsp->rts_seqlock);
801a6889becSPaul E. McKenney preempt_disable();
802a6889becSPaul E. McKenney rtsp->a = torture_random(this_cpu_ptr(&refscale_rand));
803a6889becSPaul E. McKenney preempt_enable();
804a6889becSPaul E. McKenney }
805a6889becSPaul E. McKenney
8068f35fefaSChristophe JAILLET static const struct ref_scale_ops typesafe_ref_ops;
8078f35fefaSChristophe JAILLET static const struct ref_scale_ops typesafe_lock_ops;
8088f35fefaSChristophe JAILLET static const struct ref_scale_ops typesafe_seqlock_ops;
809a6889becSPaul E. McKenney
810a6889becSPaul E. McKenney // Initialize for a typesafe test.
typesafe_init(void)811a6889becSPaul E. McKenney static bool typesafe_init(void)
812a6889becSPaul E. McKenney {
813a6889becSPaul E. McKenney long idx;
814a6889becSPaul E. McKenney long si = lookup_instances;
815a6889becSPaul E. McKenney
816a6889becSPaul E. McKenney typesafe_kmem_cachep = kmem_cache_create("refscale_typesafe",
817a6889becSPaul E. McKenney sizeof(struct refscale_typesafe), sizeof(void *),
818a6889becSPaul E. McKenney SLAB_TYPESAFE_BY_RCU, refscale_typesafe_ctor);
819a6889becSPaul E. McKenney if (!typesafe_kmem_cachep)
820a6889becSPaul E. McKenney return false;
821a6889becSPaul E. McKenney if (si < 0)
822a6889becSPaul E. McKenney si = -si * nr_cpu_ids;
823a6889becSPaul E. McKenney else if (si == 0)
824a6889becSPaul E. McKenney si = nr_cpu_ids;
825a6889becSPaul E. McKenney rtsarray_size = si;
826a6889becSPaul E. McKenney rtsarray = kcalloc(si, sizeof(*rtsarray), GFP_KERNEL);
827a6889becSPaul E. McKenney if (!rtsarray)
828a6889becSPaul E. McKenney return false;
829a6889becSPaul E. McKenney for (idx = 0; idx < rtsarray_size; idx++) {
830a6889becSPaul E. McKenney rtsarray[idx] = typesafe_alloc_one();
831a6889becSPaul E. McKenney if (!rtsarray[idx])
832a6889becSPaul E. McKenney return false;
833a6889becSPaul E. McKenney }
834a6889becSPaul E. McKenney if (cur_ops == &typesafe_ref_ops) {
835a6889becSPaul E. McKenney rts_acquire = typesafe_ref_acquire;
836a6889becSPaul E. McKenney rts_release = typesafe_ref_release;
837a6889becSPaul E. McKenney } else if (cur_ops == &typesafe_lock_ops) {
838a6889becSPaul E. McKenney rts_acquire = typesafe_lock_acquire;
839a6889becSPaul E. McKenney rts_release = typesafe_lock_release;
840a6889becSPaul E. McKenney } else if (cur_ops == &typesafe_seqlock_ops) {
841a6889becSPaul E. McKenney rts_acquire = typesafe_seqlock_acquire;
842a6889becSPaul E. McKenney rts_release = typesafe_seqlock_release;
843a6889becSPaul E. McKenney } else {
844a6889becSPaul E. McKenney WARN_ON_ONCE(1);
845a6889becSPaul E. McKenney return false;
846a6889becSPaul E. McKenney }
847a6889becSPaul E. McKenney return true;
848a6889becSPaul E. McKenney }
849a6889becSPaul E. McKenney
850a6889becSPaul E. McKenney // Clean up after a typesafe test.
typesafe_cleanup(void)851a6889becSPaul E. McKenney static void typesafe_cleanup(void)
852a6889becSPaul E. McKenney {
853a6889becSPaul E. McKenney long idx;
854a6889becSPaul E. McKenney
855a6889becSPaul E. McKenney if (rtsarray) {
856a6889becSPaul E. McKenney for (idx = 0; idx < rtsarray_size; idx++)
857a6889becSPaul E. McKenney kmem_cache_free(typesafe_kmem_cachep, rtsarray[idx]);
858a6889becSPaul E. McKenney kfree(rtsarray);
859a6889becSPaul E. McKenney rtsarray = NULL;
860a6889becSPaul E. McKenney rtsarray_size = 0;
861a6889becSPaul E. McKenney }
862a6889becSPaul E. McKenney kmem_cache_destroy(typesafe_kmem_cachep);
863a6889becSPaul E. McKenney typesafe_kmem_cachep = NULL;
864a6889becSPaul E. McKenney rts_acquire = NULL;
865a6889becSPaul E. McKenney rts_release = NULL;
866a6889becSPaul E. McKenney }
867a6889becSPaul E. McKenney
868a6889becSPaul E. McKenney // The typesafe_init() function distinguishes these structures by address.
8698f35fefaSChristophe JAILLET static const struct ref_scale_ops typesafe_ref_ops = {
870a6889becSPaul E. McKenney .init = typesafe_init,
871a6889becSPaul E. McKenney .cleanup = typesafe_cleanup,
872a6889becSPaul E. McKenney .readsection = typesafe_read_section,
873a6889becSPaul E. McKenney .delaysection = typesafe_delay_section,
874a6889becSPaul E. McKenney .name = "typesafe_ref"
875a6889becSPaul E. McKenney };
876a6889becSPaul E. McKenney
8778f35fefaSChristophe JAILLET static const struct ref_scale_ops typesafe_lock_ops = {
878a6889becSPaul E. McKenney .init = typesafe_init,
879a6889becSPaul E. McKenney .cleanup = typesafe_cleanup,
880a6889becSPaul E. McKenney .readsection = typesafe_read_section,
881a6889becSPaul E. McKenney .delaysection = typesafe_delay_section,
882a6889becSPaul E. McKenney .name = "typesafe_lock"
883a6889becSPaul E. McKenney };
884a6889becSPaul E. McKenney
8858f35fefaSChristophe JAILLET static const struct ref_scale_ops typesafe_seqlock_ops = {
886a6889becSPaul E. McKenney .init = typesafe_init,
887a6889becSPaul E. McKenney .cleanup = typesafe_cleanup,
888a6889becSPaul E. McKenney .readsection = typesafe_read_section,
889a6889becSPaul E. McKenney .delaysection = typesafe_delay_section,
890a6889becSPaul E. McKenney .name = "typesafe_seqlock"
891a6889becSPaul E. McKenney };
892a6889becSPaul E. McKenney
rcu_scale_one_reader(void)8931fbeb3a8SPaul E. McKenney static void rcu_scale_one_reader(void)
8941fbeb3a8SPaul E. McKenney {
8951fbeb3a8SPaul E. McKenney if (readdelay <= 0)
8961fbeb3a8SPaul E. McKenney cur_ops->readsection(loops);
8971fbeb3a8SPaul E. McKenney else
8981fbeb3a8SPaul E. McKenney cur_ops->delaysection(loops, readdelay / 1000, readdelay % 1000);
8991fbeb3a8SPaul E. McKenney }
9001fbeb3a8SPaul E. McKenney
901ff9ba8dbSPaul E. McKenney // Warm up cache, or, if needed run a series of rcu_scale_one_reader()
902ff9ba8dbSPaul E. McKenney // to allow multiple rcuscale guest OSes to collect mutually valid data.
rcu_scale_warm_cool(void)903ff9ba8dbSPaul E. McKenney static void rcu_scale_warm_cool(void)
904ff9ba8dbSPaul E. McKenney {
905ff9ba8dbSPaul E. McKenney unsigned long jdone = jiffies + (guest_os_delay > 0 ? guest_os_delay * HZ : -1);
906ff9ba8dbSPaul E. McKenney
907ff9ba8dbSPaul E. McKenney do {
908ff9ba8dbSPaul E. McKenney rcu_scale_one_reader();
909ff9ba8dbSPaul E. McKenney cond_resched();
910ff9ba8dbSPaul E. McKenney } while (time_before(jiffies, jdone));
911ff9ba8dbSPaul E. McKenney }
912ff9ba8dbSPaul E. McKenney
9131fbeb3a8SPaul E. McKenney // Reader kthread. Repeatedly does empty RCU read-side
9141fbeb3a8SPaul E. McKenney // critical section, minimizing update-side interference.
9151fbeb3a8SPaul E. McKenney static int
ref_scale_reader(void * arg)9161fbeb3a8SPaul E. McKenney ref_scale_reader(void *arg)
9171fbeb3a8SPaul E. McKenney {
9181fbeb3a8SPaul E. McKenney unsigned long flags;
9191fbeb3a8SPaul E. McKenney long me = (long)arg;
9201fbeb3a8SPaul E. McKenney struct reader_task *rt = &(reader_tasks[me]);
9211fbeb3a8SPaul E. McKenney u64 start;
9221fbeb3a8SPaul E. McKenney s64 duration;
9231fbeb3a8SPaul E. McKenney
924e76506f0SPaul E. McKenney VERBOSE_SCALEOUT_BATCH("ref_scale_reader %ld: task started", me);
92505bc276cSPaul E. McKenney WARN_ON_ONCE(set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids)));
9261fbeb3a8SPaul E. McKenney set_user_nice(current, MAX_NICE);
9271fbeb3a8SPaul E. McKenney atomic_inc(&n_init);
9281fbeb3a8SPaul E. McKenney if (holdoff)
9291fbeb3a8SPaul E. McKenney schedule_timeout_interruptible(holdoff * HZ);
9301fbeb3a8SPaul E. McKenney repeat:
93105bc276cSPaul E. McKenney VERBOSE_SCALEOUT_BATCH("ref_scale_reader %ld: waiting to start next experiment on cpu %d", me, raw_smp_processor_id());
9321fbeb3a8SPaul E. McKenney
9331fbeb3a8SPaul E. McKenney // Wait for signal that this reader can start.
9341fbeb3a8SPaul E. McKenney wait_event(rt->wq, (atomic_read(&nreaders_exp) && smp_load_acquire(&rt->start_reader)) ||
9351fbeb3a8SPaul E. McKenney torture_must_stop());
9361fbeb3a8SPaul E. McKenney
9371fbeb3a8SPaul E. McKenney if (torture_must_stop())
9381fbeb3a8SPaul E. McKenney goto end;
9391fbeb3a8SPaul E. McKenney
9401fbeb3a8SPaul E. McKenney // Make sure that the CPU is affinitized appropriately during testing.
941046c06f5SPaul E. McKenney WARN_ON_ONCE(raw_smp_processor_id() != me % nr_cpu_ids);
9421fbeb3a8SPaul E. McKenney
9431fbeb3a8SPaul E. McKenney WRITE_ONCE(rt->start_reader, 0);
9441fbeb3a8SPaul E. McKenney if (!atomic_dec_return(&n_started))
9451fbeb3a8SPaul E. McKenney while (atomic_read_acquire(&n_started))
9461fbeb3a8SPaul E. McKenney cpu_relax();
9471fbeb3a8SPaul E. McKenney
948e76506f0SPaul E. McKenney VERBOSE_SCALEOUT_BATCH("ref_scale_reader %ld: experiment %d started", me, exp_idx);
9491fbeb3a8SPaul E. McKenney
9501fbeb3a8SPaul E. McKenney
9511fbeb3a8SPaul E. McKenney // To reduce noise, do an initial cache-warming invocation, check
9521fbeb3a8SPaul E. McKenney // in, and then keep warming until everyone has checked in.
9531fbeb3a8SPaul E. McKenney rcu_scale_one_reader();
9541fbeb3a8SPaul E. McKenney if (!atomic_dec_return(&n_warmedup))
9551fbeb3a8SPaul E. McKenney while (atomic_read_acquire(&n_warmedup))
9561fbeb3a8SPaul E. McKenney rcu_scale_one_reader();
9571fbeb3a8SPaul E. McKenney // Also keep interrupts disabled. This also has the effect
9581fbeb3a8SPaul E. McKenney // of preventing entries into slow path for rcu_read_unlock().
9591fbeb3a8SPaul E. McKenney local_irq_save(flags);
9601fbeb3a8SPaul E. McKenney start = ktime_get_mono_fast_ns();
9611fbeb3a8SPaul E. McKenney
9621fbeb3a8SPaul E. McKenney rcu_scale_one_reader();
9631fbeb3a8SPaul E. McKenney
9641fbeb3a8SPaul E. McKenney duration = ktime_get_mono_fast_ns() - start;
9651fbeb3a8SPaul E. McKenney local_irq_restore(flags);
9661fbeb3a8SPaul E. McKenney
9671fbeb3a8SPaul E. McKenney rt->last_duration_ns = WARN_ON_ONCE(duration < 0) ? 0 : duration;
9681fbeb3a8SPaul E. McKenney // To reduce runtime-skew noise, do maintain-load invocations until
9691fbeb3a8SPaul E. McKenney // everyone is done.
9701fbeb3a8SPaul E. McKenney if (!atomic_dec_return(&n_cooleddown))
9711fbeb3a8SPaul E. McKenney while (atomic_read_acquire(&n_cooleddown))
9721fbeb3a8SPaul E. McKenney rcu_scale_one_reader();
9731fbeb3a8SPaul E. McKenney
9741fbeb3a8SPaul E. McKenney if (atomic_dec_and_test(&nreaders_exp))
9751fbeb3a8SPaul E. McKenney wake_up(&main_wq);
9761fbeb3a8SPaul E. McKenney
977e76506f0SPaul E. McKenney VERBOSE_SCALEOUT_BATCH("ref_scale_reader %ld: experiment %d ended, (readers remaining=%d)",
9781fbeb3a8SPaul E. McKenney me, exp_idx, atomic_read(&nreaders_exp));
9791fbeb3a8SPaul E. McKenney
9801fbeb3a8SPaul E. McKenney if (!torture_must_stop())
9811fbeb3a8SPaul E. McKenney goto repeat;
9821fbeb3a8SPaul E. McKenney end:
9831fbeb3a8SPaul E. McKenney torture_kthread_stopping("ref_scale_reader");
9841fbeb3a8SPaul E. McKenney return 0;
9851fbeb3a8SPaul E. McKenney }
9861fbeb3a8SPaul E. McKenney
reset_readers(void)9871fbeb3a8SPaul E. McKenney static void reset_readers(void)
9881fbeb3a8SPaul E. McKenney {
9891fbeb3a8SPaul E. McKenney int i;
9901fbeb3a8SPaul E. McKenney struct reader_task *rt;
9911fbeb3a8SPaul E. McKenney
9921fbeb3a8SPaul E. McKenney for (i = 0; i < nreaders; i++) {
9931fbeb3a8SPaul E. McKenney rt = &(reader_tasks[i]);
9941fbeb3a8SPaul E. McKenney
9951fbeb3a8SPaul E. McKenney rt->last_duration_ns = 0;
9961fbeb3a8SPaul E. McKenney }
9971fbeb3a8SPaul E. McKenney }
9981fbeb3a8SPaul E. McKenney
9991fbeb3a8SPaul E. McKenney // Print the results of each reader and return the sum of all their durations.
process_durations(int n)10001fbeb3a8SPaul E. McKenney static u64 process_durations(int n)
10011fbeb3a8SPaul E. McKenney {
10021fbeb3a8SPaul E. McKenney int i;
10031fbeb3a8SPaul E. McKenney struct reader_task *rt;
10044e39bb49SChristophe JAILLET struct seq_buf s;
10051fbeb3a8SPaul E. McKenney char *buf;
10061fbeb3a8SPaul E. McKenney u64 sum = 0;
10071fbeb3a8SPaul E. McKenney
10089880eb87SLi Zhijian buf = kmalloc(800 + 64, GFP_KERNEL);
10091fbeb3a8SPaul E. McKenney if (!buf)
10101fbeb3a8SPaul E. McKenney return 0;
10114e39bb49SChristophe JAILLET seq_buf_init(&s, buf, 800 + 64);
10124e39bb49SChristophe JAILLET
10134e39bb49SChristophe JAILLET seq_buf_printf(&s, "Experiment #%d (Format: <THREAD-NUM>:<Total loop time in ns>)",
10141fbeb3a8SPaul E. McKenney exp_idx);
10151fbeb3a8SPaul E. McKenney
10161fbeb3a8SPaul E. McKenney for (i = 0; i < n && !torture_must_stop(); i++) {
10171fbeb3a8SPaul E. McKenney rt = &(reader_tasks[i]);
10181fbeb3a8SPaul E. McKenney
10191fbeb3a8SPaul E. McKenney if (i % 5 == 0)
10204e39bb49SChristophe JAILLET seq_buf_putc(&s, '\n');
10214e39bb49SChristophe JAILLET
10224e39bb49SChristophe JAILLET if (seq_buf_used(&s) >= 800) {
10234e39bb49SChristophe JAILLET pr_alert("%s", seq_buf_str(&s));
10244e39bb49SChristophe JAILLET seq_buf_clear(&s);
10259880eb87SLi Zhijian }
10264e39bb49SChristophe JAILLET
10274e39bb49SChristophe JAILLET seq_buf_printf(&s, "%d: %llu\t", i, rt->last_duration_ns);
10281fbeb3a8SPaul E. McKenney
10291fbeb3a8SPaul E. McKenney sum += rt->last_duration_ns;
10301fbeb3a8SPaul E. McKenney }
10314e39bb49SChristophe JAILLET pr_alert("%s\n", seq_buf_str(&s));
10321fbeb3a8SPaul E. McKenney
10331fbeb3a8SPaul E. McKenney kfree(buf);
10341fbeb3a8SPaul E. McKenney return sum;
10351fbeb3a8SPaul E. McKenney }
10361fbeb3a8SPaul E. McKenney
10371fbeb3a8SPaul E. McKenney // The main_func is the main orchestrator, it performs a bunch of
10381fbeb3a8SPaul E. McKenney // experiments. For every experiment, it orders all the readers
10391fbeb3a8SPaul E. McKenney // involved to start and waits for them to finish the experiment. It
10401fbeb3a8SPaul E. McKenney // then reads their timestamps and starts the next experiment. Each
10411fbeb3a8SPaul E. McKenney // experiment progresses from 1 concurrent reader to N of them at which
10421fbeb3a8SPaul E. McKenney // point all the timestamps are printed.
main_func(void * arg)10431fbeb3a8SPaul E. McKenney static int main_func(void *arg)
10441fbeb3a8SPaul E. McKenney {
10451fbeb3a8SPaul E. McKenney int exp, r;
10461fbeb3a8SPaul E. McKenney char buf1[64];
10471fbeb3a8SPaul E. McKenney char *buf;
10481fbeb3a8SPaul E. McKenney u64 *result_avg;
10491fbeb3a8SPaul E. McKenney
10501fbeb3a8SPaul E. McKenney set_cpus_allowed_ptr(current, cpumask_of(nreaders % nr_cpu_ids));
10511fbeb3a8SPaul E. McKenney set_user_nice(current, MAX_NICE);
10521fbeb3a8SPaul E. McKenney
10531fbeb3a8SPaul E. McKenney VERBOSE_SCALEOUT("main_func task started");
10541fbeb3a8SPaul E. McKenney result_avg = kzalloc(nruns * sizeof(*result_avg), GFP_KERNEL);
10559880eb87SLi Zhijian buf = kzalloc(800 + 64, GFP_KERNEL);
10561fbeb3a8SPaul E. McKenney if (!result_avg || !buf) {
10574feeb9d5SLi Zhijian SCALEOUT_ERRSTRING("out of memory");
1058c30c8763SLi Zhijian goto oom_exit;
10591fbeb3a8SPaul E. McKenney }
10601fbeb3a8SPaul E. McKenney if (holdoff)
10611fbeb3a8SPaul E. McKenney schedule_timeout_interruptible(holdoff * HZ);
10621fbeb3a8SPaul E. McKenney
10631fbeb3a8SPaul E. McKenney // Wait for all threads to start.
10641fbeb3a8SPaul E. McKenney atomic_inc(&n_init);
10651fbeb3a8SPaul E. McKenney while (atomic_read(&n_init) < nreaders + 1)
10661fbeb3a8SPaul E. McKenney schedule_timeout_uninterruptible(1);
10671fbeb3a8SPaul E. McKenney
10681fbeb3a8SPaul E. McKenney // Start exp readers up per experiment
1069ff9ba8dbSPaul E. McKenney rcu_scale_warm_cool();
10701fbeb3a8SPaul E. McKenney for (exp = 0; exp < nruns && !torture_must_stop(); exp++) {
10711fbeb3a8SPaul E. McKenney if (torture_must_stop())
10721fbeb3a8SPaul E. McKenney goto end;
10731fbeb3a8SPaul E. McKenney
10741fbeb3a8SPaul E. McKenney reset_readers();
10751fbeb3a8SPaul E. McKenney atomic_set(&nreaders_exp, nreaders);
10761fbeb3a8SPaul E. McKenney atomic_set(&n_started, nreaders);
10771fbeb3a8SPaul E. McKenney atomic_set(&n_warmedup, nreaders);
10781fbeb3a8SPaul E. McKenney atomic_set(&n_cooleddown, nreaders);
10791fbeb3a8SPaul E. McKenney
10801fbeb3a8SPaul E. McKenney exp_idx = exp;
10811fbeb3a8SPaul E. McKenney
10821fbeb3a8SPaul E. McKenney for (r = 0; r < nreaders; r++) {
10831fbeb3a8SPaul E. McKenney smp_store_release(&reader_tasks[r].start_reader, 1);
10841fbeb3a8SPaul E. McKenney wake_up(&reader_tasks[r].wq);
10851fbeb3a8SPaul E. McKenney }
10861fbeb3a8SPaul E. McKenney
10871fbeb3a8SPaul E. McKenney VERBOSE_SCALEOUT("main_func: experiment started, waiting for %d readers",
10881fbeb3a8SPaul E. McKenney nreaders);
10891fbeb3a8SPaul E. McKenney
10901fbeb3a8SPaul E. McKenney wait_event(main_wq,
10911fbeb3a8SPaul E. McKenney !atomic_read(&nreaders_exp) || torture_must_stop());
10921fbeb3a8SPaul E. McKenney
10931fbeb3a8SPaul E. McKenney VERBOSE_SCALEOUT("main_func: experiment ended");
10941fbeb3a8SPaul E. McKenney
10951fbeb3a8SPaul E. McKenney if (torture_must_stop())
10961fbeb3a8SPaul E. McKenney goto end;
10971fbeb3a8SPaul E. McKenney
10981fbeb3a8SPaul E. McKenney result_avg[exp] = div_u64(1000 * process_durations(nreaders), nreaders * loops);
10991fbeb3a8SPaul E. McKenney }
1100ff9ba8dbSPaul E. McKenney rcu_scale_warm_cool();
11011fbeb3a8SPaul E. McKenney
11021fbeb3a8SPaul E. McKenney // Print the average of all experiments
11031fbeb3a8SPaul E. McKenney SCALEOUT("END OF TEST. Calculating average duration per loop (nanoseconds)...\n");
11041fbeb3a8SPaul E. McKenney
11059880eb87SLi Zhijian pr_alert("Runs\tTime(ns)\n");
11061fbeb3a8SPaul E. McKenney for (exp = 0; exp < nruns; exp++) {
11071fbeb3a8SPaul E. McKenney u64 avg;
11081fbeb3a8SPaul E. McKenney u32 rem;
11091fbeb3a8SPaul E. McKenney
11101fbeb3a8SPaul E. McKenney avg = div_u64_rem(result_avg[exp], 1000, &rem);
11111fbeb3a8SPaul E. McKenney sprintf(buf1, "%d\t%llu.%03u\n", exp + 1, avg, rem);
11121fbeb3a8SPaul E. McKenney strcat(buf, buf1);
11139880eb87SLi Zhijian if (strlen(buf) >= 800) {
11149880eb87SLi Zhijian pr_alert("%s", buf);
11159880eb87SLi Zhijian buf[0] = 0;
11169880eb87SLi Zhijian }
11171fbeb3a8SPaul E. McKenney }
11181fbeb3a8SPaul E. McKenney
11199880eb87SLi Zhijian pr_alert("%s", buf);
11201fbeb3a8SPaul E. McKenney
1121c30c8763SLi Zhijian oom_exit:
11221fbeb3a8SPaul E. McKenney // This will shutdown everything including us.
11231fbeb3a8SPaul E. McKenney if (shutdown) {
11241fbeb3a8SPaul E. McKenney shutdown_start = 1;
11251fbeb3a8SPaul E. McKenney wake_up(&shutdown_wq);
11261fbeb3a8SPaul E. McKenney }
11271fbeb3a8SPaul E. McKenney
11281fbeb3a8SPaul E. McKenney // Wait for torture to stop us
11291fbeb3a8SPaul E. McKenney while (!torture_must_stop())
11301fbeb3a8SPaul E. McKenney schedule_timeout_uninterruptible(1);
11311fbeb3a8SPaul E. McKenney
11321fbeb3a8SPaul E. McKenney end:
11331fbeb3a8SPaul E. McKenney torture_kthread_stopping("main_func");
11341fbeb3a8SPaul E. McKenney kfree(result_avg);
11351fbeb3a8SPaul E. McKenney kfree(buf);
11361fbeb3a8SPaul E. McKenney return 0;
11371fbeb3a8SPaul E. McKenney }
11381fbeb3a8SPaul E. McKenney
11391fbeb3a8SPaul E. McKenney static void
ref_scale_print_module_parms(const struct ref_scale_ops * cur_ops,const char * tag)11408f35fefaSChristophe JAILLET ref_scale_print_module_parms(const struct ref_scale_ops *cur_ops, const char *tag)
11411fbeb3a8SPaul E. McKenney {
11421fbeb3a8SPaul E. McKenney pr_alert("%s" SCALE_FLAG
1143d6fea1ddSPaul E. McKenney "--- %s: verbose=%d verbose_batched=%d shutdown=%d holdoff=%d lookup_instances=%ld loops=%ld nreaders=%d nruns=%d readdelay=%d\n", scale_type, tag,
1144d6fea1ddSPaul E. McKenney verbose, verbose_batched, shutdown, holdoff, lookup_instances, loops, nreaders, nruns, readdelay);
11451fbeb3a8SPaul E. McKenney }
11461fbeb3a8SPaul E. McKenney
11471fbeb3a8SPaul E. McKenney static void
ref_scale_cleanup(void)11481fbeb3a8SPaul E. McKenney ref_scale_cleanup(void)
11491fbeb3a8SPaul E. McKenney {
11501fbeb3a8SPaul E. McKenney int i;
11511fbeb3a8SPaul E. McKenney
11521fbeb3a8SPaul E. McKenney if (torture_cleanup_begin())
11531fbeb3a8SPaul E. McKenney return;
11541fbeb3a8SPaul E. McKenney
11551fbeb3a8SPaul E. McKenney if (!cur_ops) {
11561fbeb3a8SPaul E. McKenney torture_cleanup_end();
11571fbeb3a8SPaul E. McKenney return;
11581fbeb3a8SPaul E. McKenney }
11591fbeb3a8SPaul E. McKenney
11601fbeb3a8SPaul E. McKenney if (reader_tasks) {
11611fbeb3a8SPaul E. McKenney for (i = 0; i < nreaders; i++)
11621fbeb3a8SPaul E. McKenney torture_stop_kthread("ref_scale_reader",
11631fbeb3a8SPaul E. McKenney reader_tasks[i].task);
11641fbeb3a8SPaul E. McKenney }
11651fbeb3a8SPaul E. McKenney kfree(reader_tasks);
11661fbeb3a8SPaul E. McKenney
11671fbeb3a8SPaul E. McKenney torture_stop_kthread("main_task", main_task);
11681fbeb3a8SPaul E. McKenney kfree(main_task);
11691fbeb3a8SPaul E. McKenney
11701fbeb3a8SPaul E. McKenney // Do scale-type-specific cleanup operations.
11711fbeb3a8SPaul E. McKenney if (cur_ops->cleanup != NULL)
11721fbeb3a8SPaul E. McKenney cur_ops->cleanup();
11731fbeb3a8SPaul E. McKenney
11741fbeb3a8SPaul E. McKenney torture_cleanup_end();
11751fbeb3a8SPaul E. McKenney }
11761fbeb3a8SPaul E. McKenney
11771fbeb3a8SPaul E. McKenney // Shutdown kthread. Just waits to be awakened, then shuts down system.
11781fbeb3a8SPaul E. McKenney static int
ref_scale_shutdown(void * arg)11791fbeb3a8SPaul E. McKenney ref_scale_shutdown(void *arg)
11801fbeb3a8SPaul E. McKenney {
11816bc6e6b2SPaul E. McKenney wait_event_idle(shutdown_wq, shutdown_start);
11821fbeb3a8SPaul E. McKenney
11831fbeb3a8SPaul E. McKenney smp_mb(); // Wake before output.
11841fbeb3a8SPaul E. McKenney ref_scale_cleanup();
11851fbeb3a8SPaul E. McKenney kernel_power_off();
11861fbeb3a8SPaul E. McKenney
11871fbeb3a8SPaul E. McKenney return -EINVAL;
11881fbeb3a8SPaul E. McKenney }
11891fbeb3a8SPaul E. McKenney
11901fbeb3a8SPaul E. McKenney static int __init
ref_scale_init(void)11911fbeb3a8SPaul E. McKenney ref_scale_init(void)
11921fbeb3a8SPaul E. McKenney {
11931fbeb3a8SPaul E. McKenney long i;
11941fbeb3a8SPaul E. McKenney int firsterr = 0;
11958f35fefaSChristophe JAILLET static const struct ref_scale_ops *scale_ops[] = {
1196*4c3fca0fSPaul E. McKenney &rcu_ops, &srcu_ops, &srcu_fast_ops, &srcu_lite_ops, RCU_TRACE_OPS RCU_TASKS_OPS
11971806b1f9SPaul E. McKenney &refcnt_ops, &rwlock_ops, &rwsem_ops, &lock_ops, &lock_irq_ops,
11981806b1f9SPaul E. McKenney &acqrel_ops, &sched_clock_ops, &clock_ops, &jiffies_ops,
11991806b1f9SPaul E. McKenney &typesafe_ref_ops, &typesafe_lock_ops, &typesafe_seqlock_ops,
12001fbeb3a8SPaul E. McKenney };
12011fbeb3a8SPaul E. McKenney
12021fbeb3a8SPaul E. McKenney if (!torture_init_begin(scale_type, verbose))
12031fbeb3a8SPaul E. McKenney return -EBUSY;
12041fbeb3a8SPaul E. McKenney
12051fbeb3a8SPaul E. McKenney for (i = 0; i < ARRAY_SIZE(scale_ops); i++) {
12061fbeb3a8SPaul E. McKenney cur_ops = scale_ops[i];
12071fbeb3a8SPaul E. McKenney if (strcmp(scale_type, cur_ops->name) == 0)
12081fbeb3a8SPaul E. McKenney break;
12091fbeb3a8SPaul E. McKenney }
12101fbeb3a8SPaul E. McKenney if (i == ARRAY_SIZE(scale_ops)) {
12111fbeb3a8SPaul E. McKenney pr_alert("rcu-scale: invalid scale type: \"%s\"\n", scale_type);
12121fbeb3a8SPaul E. McKenney pr_alert("rcu-scale types:");
12131fbeb3a8SPaul E. McKenney for (i = 0; i < ARRAY_SIZE(scale_ops); i++)
12141fbeb3a8SPaul E. McKenney pr_cont(" %s", scale_ops[i]->name);
12151fbeb3a8SPaul E. McKenney pr_cont("\n");
12161fbeb3a8SPaul E. McKenney firsterr = -EINVAL;
12171fbeb3a8SPaul E. McKenney cur_ops = NULL;
12181fbeb3a8SPaul E. McKenney goto unwind;
12191fbeb3a8SPaul E. McKenney }
12201fbeb3a8SPaul E. McKenney if (cur_ops->init)
12213c6496c8SPaul E. McKenney if (!cur_ops->init()) {
12223c6496c8SPaul E. McKenney firsterr = -EUCLEAN;
12233c6496c8SPaul E. McKenney goto unwind;
12243c6496c8SPaul E. McKenney }
12251fbeb3a8SPaul E. McKenney
12261fbeb3a8SPaul E. McKenney ref_scale_print_module_parms(cur_ops, "Start of test");
12271fbeb3a8SPaul E. McKenney
12281fbeb3a8SPaul E. McKenney // Shutdown task
12291fbeb3a8SPaul E. McKenney if (shutdown) {
12301fbeb3a8SPaul E. McKenney init_waitqueue_head(&shutdown_wq);
12311fbeb3a8SPaul E. McKenney firsterr = torture_create_kthread(ref_scale_shutdown, NULL,
12321fbeb3a8SPaul E. McKenney shutdown_task);
1233ed60ad73SPaul E. McKenney if (torture_init_error(firsterr))
12341fbeb3a8SPaul E. McKenney goto unwind;
12351fbeb3a8SPaul E. McKenney schedule_timeout_uninterruptible(1);
12361fbeb3a8SPaul E. McKenney }
12371fbeb3a8SPaul E. McKenney
12381fbeb3a8SPaul E. McKenney // Reader tasks (default to ~75% of online CPUs).
12391fbeb3a8SPaul E. McKenney if (nreaders < 0)
12401fbeb3a8SPaul E. McKenney nreaders = (num_online_cpus() >> 1) + (num_online_cpus() >> 2);
12410c6d18d8SPaul E. McKenney if (WARN_ONCE(loops <= 0, "%s: loops = %ld, adjusted to 1\n", __func__, loops))
12420c6d18d8SPaul E. McKenney loops = 1;
12430c6d18d8SPaul E. McKenney if (WARN_ONCE(nreaders <= 0, "%s: nreaders = %d, adjusted to 1\n", __func__, nreaders))
12440c6d18d8SPaul E. McKenney nreaders = 1;
12450c6d18d8SPaul E. McKenney if (WARN_ONCE(nruns <= 0, "%s: nruns = %d, adjusted to 1\n", __func__, nruns))
12460c6d18d8SPaul E. McKenney nruns = 1;
12471fbeb3a8SPaul E. McKenney reader_tasks = kcalloc(nreaders, sizeof(reader_tasks[0]),
12481fbeb3a8SPaul E. McKenney GFP_KERNEL);
12491fbeb3a8SPaul E. McKenney if (!reader_tasks) {
12504feeb9d5SLi Zhijian SCALEOUT_ERRSTRING("out of memory");
12511fbeb3a8SPaul E. McKenney firsterr = -ENOMEM;
12521fbeb3a8SPaul E. McKenney goto unwind;
12531fbeb3a8SPaul E. McKenney }
12541fbeb3a8SPaul E. McKenney
1255f71f22b6SLi Zhijian VERBOSE_SCALEOUT("Starting %d reader threads", nreaders);
12561fbeb3a8SPaul E. McKenney
12571fbeb3a8SPaul E. McKenney for (i = 0; i < nreaders; i++) {
1258f5063e89SWaiman Long init_waitqueue_head(&reader_tasks[i].wq);
12591fbeb3a8SPaul E. McKenney firsterr = torture_create_kthread(ref_scale_reader, (void *)i,
12601fbeb3a8SPaul E. McKenney reader_tasks[i].task);
1261ed60ad73SPaul E. McKenney if (torture_init_error(firsterr))
12621fbeb3a8SPaul E. McKenney goto unwind;
12631fbeb3a8SPaul E. McKenney }
12641fbeb3a8SPaul E. McKenney
12651fbeb3a8SPaul E. McKenney // Main Task
12661fbeb3a8SPaul E. McKenney init_waitqueue_head(&main_wq);
12671fbeb3a8SPaul E. McKenney firsterr = torture_create_kthread(main_func, NULL, main_task);
1268ed60ad73SPaul E. McKenney if (torture_init_error(firsterr))
12691fbeb3a8SPaul E. McKenney goto unwind;
12701fbeb3a8SPaul E. McKenney
12711fbeb3a8SPaul E. McKenney torture_init_end();
12721fbeb3a8SPaul E. McKenney return 0;
12731fbeb3a8SPaul E. McKenney
12741fbeb3a8SPaul E. McKenney unwind:
12751fbeb3a8SPaul E. McKenney torture_init_end();
12761fbeb3a8SPaul E. McKenney ref_scale_cleanup();
1277bc80d353SPaul E. McKenney if (shutdown) {
1278bc80d353SPaul E. McKenney WARN_ON(!IS_MODULE(CONFIG_RCU_REF_SCALE_TEST));
1279bc80d353SPaul E. McKenney kernel_power_off();
1280bc80d353SPaul E. McKenney }
12811fbeb3a8SPaul E. McKenney return firsterr;
12821fbeb3a8SPaul E. McKenney }
12831fbeb3a8SPaul E. McKenney
12841fbeb3a8SPaul E. McKenney module_init(ref_scale_init);
12851fbeb3a8SPaul E. McKenney module_exit(ref_scale_cleanup);
1286