···41574157 rcu_node tree with an eye towards determining41584158 why a new grace period has not yet started.4159415941604160- rcuperf.gp_async= [KNL]41604160+ rcuscale.gp_async= [KNL]41614161 Measure performance of asynchronous41624162 grace-period primitives such as call_rcu().4163416341644164- rcuperf.gp_async_max= [KNL]41644164+ rcuscale.gp_async_max= [KNL]41654165 Specify the maximum number of outstanding41664166 callbacks per writer thread. When a writer41674167 thread exceeds this limit, it invokes the41684168 corresponding flavor of rcu_barrier() to allow41694169 previously posted callbacks to drain.4170417041714171- rcuperf.gp_exp= [KNL]41714171+ rcuscale.gp_exp= [KNL]41724172 Measure performance of expedited synchronous41734173 grace-period primitives.4174417441754175- rcuperf.holdoff= [KNL]41754175+ rcuscale.holdoff= [KNL]41764176 Set test-start holdoff period. The purpose of41774177 this parameter is to delay the start of the41784178 test until boot completes in order to avoid41794179 interference.4180418041814181- rcuperf.kfree_rcu_test= [KNL]41814181+ rcuscale.kfree_rcu_test= [KNL]41824182 Set to measure performance of kfree_rcu() flooding.4183418341844184- rcuperf.kfree_nthreads= [KNL]41844184+ rcuscale.kfree_nthreads= [KNL]41854185 The number of threads running loops of kfree_rcu().4186418641874187- rcuperf.kfree_alloc_num= [KNL]41874187+ rcuscale.kfree_alloc_num= [KNL]41884188 Number of allocations and frees done in an iteration.4189418941904190- rcuperf.kfree_loops= [KNL]41914191- Number of loops doing rcuperf.kfree_alloc_num number41904190+ rcuscale.kfree_loops= [KNL]41914191+ Number of loops doing rcuscale.kfree_alloc_num number41924192 of allocations and frees.4193419341944194- rcuperf.nreaders= [KNL]41944194+ rcuscale.nreaders= [KNL]41954195 Set number of RCU readers. The value -1 selects41964196 N, where N is the number of CPUs. A value41974197 "n" less than -1 selects N-n+1, where N is again···42004200 A value of "n" less than or equal to -N selects42014201 a single reader.4202420242034203- rcuperf.nwriters= [KNL]42034203+ rcuscale.nwriters= [KNL]42044204 Set number of RCU writers. The values operate42054205- the same as for rcuperf.nreaders.42054205+ the same as for rcuscale.nreaders.42064206 N, where N is the number of CPUs4207420742084208- rcuperf.perf_type= [KNL]42084208+ rcuscale.perf_type= [KNL]42094209 Specify the RCU implementation to test.4210421042114211- rcuperf.shutdown= [KNL]42114211+ rcuscale.shutdown= [KNL]42124212 Shut the system down after performance tests42134213 complete. This is useful for hands-off automated42144214 testing.4215421542164216- rcuperf.verbose= [KNL]42164216+ rcuscale.verbose= [KNL]42174217 Enable additional printk() statements.4218421842194219- rcuperf.writer_holdoff= [KNL]42194219+ rcuscale.writer_holdoff= [KNL]42204220 Write-side holdoff between grace periods,42214221 in microseconds. The default of zero says42224222 no holdoff.···45024502 refscale.shutdown= [KNL]45034503 Shut down the system at the end of the performance45044504 test. This defaults to 1 (shut it down) when45054505- rcuperf is built into the kernel and to 0 (leave45064506- it running) when rcuperf is built as a module.45054505+ refscale is built into the kernel and to 0 (leave45064506+ it running) when refscale is built as a module.4507450745084508 refscale.verbose= [KNL]45094509 Enable additional printk() statements.···46484648 and so on.46494649 Format: integer between 0 and 1046504650 Default is 0.46514651+46524652+ scftorture.holdoff= [KNL]46534653+ Number of seconds to hold off before starting46544654+ test. Defaults to zero for module insertion and46554655+ to 10 seconds for built-in smp_call_function()46564656+ tests.46574657+46584658+ scftorture.longwait= [KNL]46594659+ Request ridiculously long waits randomly selected46604660+ up to the chosen limit in seconds. Zero (the46614661+ default) disables this feature. Please note46624662+ that requesting even small non-zero numbers of46634663+ seconds can result in RCU CPU stall warnings,46644664+ softlockup complaints, and so on.46654665+46664666+ scftorture.nthreads= [KNL]46674667+ Number of kthreads to spawn to invoke the46684668+ smp_call_function() family of functions.46694669+ The default of -1 specifies a number of kthreads46704670+ equal to the number of CPUs.46714671+46724672+ scftorture.onoff_holdoff= [KNL]46734673+ Number seconds to wait after the start of the46744674+ test before initiating CPU-hotplug operations.46754675+46764676+ scftorture.onoff_interval= [KNL]46774677+ Number seconds to wait between successive46784678+ CPU-hotplug operations. Specifying zero (which46794679+ is the default) disables CPU-hotplug operations.46804680+46814681+ scftorture.shutdown_secs= [KNL]46824682+ The number of seconds following the start of the46834683+ test after which to shut down the system. The46844684+ default of zero avoids shutting down the system.46854685+ Non-zero values are useful for automated tests.46864686+46874687+ scftorture.stat_interval= [KNL]46884688+ The number of seconds between outputting the46894689+ current test statistics to the console. A value46904690+ of zero disables statistics output.46914691+46924692+ scftorture.stutter_cpus= [KNL]46934693+ The number of jiffies to wait between each change46944694+ to the set of CPUs under test.46954695+46964696+ scftorture.use_cpus_read_lock= [KNL]46974697+ Use use_cpus_read_lock() instead of the default46984698+ preempt_disable() to disable CPU hotplug46994699+ while invoking one of the smp_call_function*()47004700+ functions.47014701+47024702+ scftorture.verbose= [KNL]47034703+ Enable additional printk() statements.47044704+47054705+ scftorture.weight_single= [KNL]47064706+ The probability weighting to use for the47074707+ smp_call_function_single() function with a zero47084708+ "wait" parameter. A value of -1 selects the47094709+ default if all other weights are -1. However,47104710+ if at least one weight has some other value, a47114711+ value of -1 will instead select a weight of zero.47124712+47134713+ scftorture.weight_single_wait= [KNL]47144714+ The probability weighting to use for the47154715+ smp_call_function_single() function with a47164716+ non-zero "wait" parameter. See weight_single.47174717+47184718+ scftorture.weight_many= [KNL]47194719+ The probability weighting to use for the47204720+ smp_call_function_many() function with a zero47214721+ "wait" parameter. See weight_single.47224722+ Note well that setting a high probability for47234723+ this weighting can place serious IPI load47244724+ on the system.47254725+47264726+ scftorture.weight_many_wait= [KNL]47274727+ The probability weighting to use for the47284728+ smp_call_function_many() function with a47294729+ non-zero "wait" parameter. See weight_single47304730+ and weight_many.47314731+47324732+ scftorture.weight_all= [KNL]47334733+ The probability weighting to use for the47344734+ smp_call_function_all() function with a zero47354735+ "wait" parameter. See weight_single and47364736+ weight_many.47374737+47384738+ scftorture.weight_all_wait= [KNL]47394739+ The probability weighting to use for the47404740+ smp_call_function_all() function with a47414741+ non-zero "wait" parameter. See weight_single47424742+ and weight_many.4651474346524744 skew_tick= [KNL] Offset the periodic timer tick per cpu to mitigate46534745 xtime_lock contention on larger systems, and/or RCU lock
···11// SPDX-License-Identifier: GPL-2.0+22/*33- * Read-Copy Update module-based performance-test facility33+ * Read-Copy Update module-based scalability-test facility44 *55 * Copyright (C) IBM Corporation, 201566 *···4444MODULE_LICENSE("GPL");4545MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");46464747-#define PERF_FLAG "-perf:"4848-#define PERFOUT_STRING(s) \4949- pr_alert("%s" PERF_FLAG " %s\n", perf_type, s)5050-#define VERBOSE_PERFOUT_STRING(s) \5151- do { if (verbose) pr_alert("%s" PERF_FLAG " %s\n", perf_type, s); } while (0)5252-#define VERBOSE_PERFOUT_ERRSTRING(s) \5353- do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } while (0)4747+#define SCALE_FLAG "-scale:"4848+#define SCALEOUT_STRING(s) \4949+ pr_alert("%s" SCALE_FLAG " %s\n", scale_type, s)5050+#define VERBOSE_SCALEOUT_STRING(s) \5151+ do { if (verbose) pr_alert("%s" SCALE_FLAG " %s\n", scale_type, s); } while (0)5252+#define VERBOSE_SCALEOUT_ERRSTRING(s) \5353+ do { if (verbose) pr_alert("%s" SCALE_FLAG "!!! %s\n", scale_type, s); } while (0)54545555/*5656 * The intended use cases for the nreaders and nwriters module parameters···6161 * nr_cpus for a mixed reader/writer test.6262 *6363 * 2. Specify the nr_cpus kernel boot parameter, but set6464- * rcuperf.nreaders to zero. This will set nwriters to the6464+ * rcuscale.nreaders to zero. This will set nwriters to the6565 * value specified by nr_cpus for an update-only test.6666 *6767 * 3. Specify the nr_cpus kernel boot parameter, but set6868- * rcuperf.nwriters to zero. This will set nreaders to the6868+ * rcuscale.nwriters to zero. This will set nreaders to the6969 * value specified by nr_cpus for a read-only test.7070 *7171 * Various other use cases may of course be specified.7272 *7373 * Note that this test's readers are intended only as a test load for7474- * the writers. The reader performance statistics will be overly7474+ * the writers. The reader scalability statistics will be overly7575 * pessimistic due to the per-critical-section interrupt disabling,7676 * test-end checks, and the pair of calls through pointers.7777 */78787979#ifdef MODULE8080-# define RCUPERF_SHUTDOWN 08080+# define RCUSCALE_SHUTDOWN 08181#else8282-# define RCUPERF_SHUTDOWN 18282+# define RCUSCALE_SHUTDOWN 18383#endif84848585torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives");···8888torture_param(int, holdoff, 10, "Holdoff time before test start (s)");8989torture_param(int, nreaders, -1, "Number of RCU reader threads");9090torture_param(int, nwriters, -1, "Number of RCU updater threads");9191-torture_param(bool, shutdown, RCUPERF_SHUTDOWN,9292- "Shutdown at end of performance tests.");9191+torture_param(bool, shutdown, RCUSCALE_SHUTDOWN,9292+ "Shutdown at end of scalability tests.");9393torture_param(int, verbose, 1, "Enable verbose debugging printk()s");9494torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");9595-torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() perf test?");9595+torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() scale test?");9696torture_param(int, kfree_mult, 1, "Multiple of kfree_obj size to allocate.");97979898-static char *perf_type = "rcu";9999-module_param(perf_type, charp, 0444);100100-MODULE_PARM_DESC(perf_type, "Type of RCU to performance-test (rcu, srcu, ...)");9898+static char *scale_type = "rcu";9999+module_param(scale_type, charp, 0444);100100+MODULE_PARM_DESC(scale_type, "Type of RCU to scalability-test (rcu, srcu, ...)");101101102102static int nrealreaders;103103static int nrealwriters;···107107108108static u64 **writer_durations;109109static int *writer_n_durations;110110-static atomic_t n_rcu_perf_reader_started;111111-static atomic_t n_rcu_perf_writer_started;112112-static atomic_t n_rcu_perf_writer_finished;110110+static atomic_t n_rcu_scale_reader_started;111111+static atomic_t n_rcu_scale_writer_started;112112+static atomic_t n_rcu_scale_writer_finished;113113static wait_queue_head_t shutdown_wq;114114-static u64 t_rcu_perf_writer_started;115115-static u64 t_rcu_perf_writer_finished;114114+static u64 t_rcu_scale_writer_started;115115+static u64 t_rcu_scale_writer_finished;116116static unsigned long b_rcu_gp_test_started;117117static unsigned long b_rcu_gp_test_finished;118118static DEFINE_PER_CPU(atomic_t, n_async_inflight);···124124 * Operations vector for selecting different types of tests.125125 */126126127127-struct rcu_perf_ops {127127+struct rcu_scale_ops {128128 int ptype;129129 void (*init)(void);130130 void (*cleanup)(void);···140140 const char *name;141141};142142143143-static struct rcu_perf_ops *cur_ops;143143+static struct rcu_scale_ops *cur_ops;144144145145/*146146- * Definitions for rcu perf testing.146146+ * Definitions for rcu scalability testing.147147 */148148149149-static int rcu_perf_read_lock(void) __acquires(RCU)149149+static int rcu_scale_read_lock(void) __acquires(RCU)150150{151151 rcu_read_lock();152152 return 0;153153}154154155155-static void rcu_perf_read_unlock(int idx) __releases(RCU)155155+static void rcu_scale_read_unlock(int idx) __releases(RCU)156156{157157 rcu_read_unlock();158158}···162162 return 0;163163}164164165165-static void rcu_sync_perf_init(void)165165+static void rcu_sync_scale_init(void)166166{167167}168168169169-static struct rcu_perf_ops rcu_ops = {169169+static struct rcu_scale_ops rcu_ops = {170170 .ptype = RCU_FLAVOR,171171- .init = rcu_sync_perf_init,172172- .readlock = rcu_perf_read_lock,173173- .readunlock = rcu_perf_read_unlock,171171+ .init = rcu_sync_scale_init,172172+ .readlock = rcu_scale_read_lock,173173+ .readunlock = rcu_scale_read_unlock,174174 .get_gp_seq = rcu_get_gp_seq,175175 .gp_diff = rcu_seq_diff,176176 .exp_completed = rcu_exp_batches_completed,···182182};183183184184/*185185- * Definitions for srcu perf testing.185185+ * Definitions for srcu scalability testing.186186 */187187188188-DEFINE_STATIC_SRCU(srcu_ctl_perf);189189-static struct srcu_struct *srcu_ctlp = &srcu_ctl_perf;188188+DEFINE_STATIC_SRCU(srcu_ctl_scale);189189+static struct srcu_struct *srcu_ctlp = &srcu_ctl_scale;190190191191-static int srcu_perf_read_lock(void) __acquires(srcu_ctlp)191191+static int srcu_scale_read_lock(void) __acquires(srcu_ctlp)192192{193193 return srcu_read_lock(srcu_ctlp);194194}195195196196-static void srcu_perf_read_unlock(int idx) __releases(srcu_ctlp)196196+static void srcu_scale_read_unlock(int idx) __releases(srcu_ctlp)197197{198198 srcu_read_unlock(srcu_ctlp, idx);199199}200200201201-static unsigned long srcu_perf_completed(void)201201+static unsigned long srcu_scale_completed(void)202202{203203 return srcu_batches_completed(srcu_ctlp);204204}···213213 srcu_barrier(srcu_ctlp);214214}215215216216-static void srcu_perf_synchronize(void)216216+static void srcu_scale_synchronize(void)217217{218218 synchronize_srcu(srcu_ctlp);219219}220220221221-static void srcu_perf_synchronize_expedited(void)221221+static void srcu_scale_synchronize_expedited(void)222222{223223 synchronize_srcu_expedited(srcu_ctlp);224224}225225226226-static struct rcu_perf_ops srcu_ops = {226226+static struct rcu_scale_ops srcu_ops = {227227 .ptype = SRCU_FLAVOR,228228- .init = rcu_sync_perf_init,229229- .readlock = srcu_perf_read_lock,230230- .readunlock = srcu_perf_read_unlock,231231- .get_gp_seq = srcu_perf_completed,228228+ .init = rcu_sync_scale_init,229229+ .readlock = srcu_scale_read_lock,230230+ .readunlock = srcu_scale_read_unlock,231231+ .get_gp_seq = srcu_scale_completed,232232 .gp_diff = rcu_seq_diff,233233- .exp_completed = srcu_perf_completed,233233+ .exp_completed = srcu_scale_completed,234234 .async = srcu_call_rcu,235235 .gp_barrier = srcu_rcu_barrier,236236- .sync = srcu_perf_synchronize,237237- .exp_sync = srcu_perf_synchronize_expedited,236236+ .sync = srcu_scale_synchronize,237237+ .exp_sync = srcu_scale_synchronize_expedited,238238 .name = "srcu"239239};240240241241static struct srcu_struct srcud;242242243243-static void srcu_sync_perf_init(void)243243+static void srcu_sync_scale_init(void)244244{245245 srcu_ctlp = &srcud;246246 init_srcu_struct(srcu_ctlp);247247}248248249249-static void srcu_sync_perf_cleanup(void)249249+static void srcu_sync_scale_cleanup(void)250250{251251 cleanup_srcu_struct(srcu_ctlp);252252}253253254254-static struct rcu_perf_ops srcud_ops = {254254+static struct rcu_scale_ops srcud_ops = {255255 .ptype = SRCU_FLAVOR,256256- .init = srcu_sync_perf_init,257257- .cleanup = srcu_sync_perf_cleanup,258258- .readlock = srcu_perf_read_lock,259259- .readunlock = srcu_perf_read_unlock,260260- .get_gp_seq = srcu_perf_completed,256256+ .init = srcu_sync_scale_init,257257+ .cleanup = srcu_sync_scale_cleanup,258258+ .readlock = srcu_scale_read_lock,259259+ .readunlock = srcu_scale_read_unlock,260260+ .get_gp_seq = srcu_scale_completed,261261 .gp_diff = rcu_seq_diff,262262- .exp_completed = srcu_perf_completed,262262+ .exp_completed = srcu_scale_completed,263263 .async = srcu_call_rcu,264264 .gp_barrier = srcu_rcu_barrier,265265- .sync = srcu_perf_synchronize,266266- .exp_sync = srcu_perf_synchronize_expedited,265265+ .sync = srcu_scale_synchronize,266266+ .exp_sync = srcu_scale_synchronize_expedited,267267 .name = "srcud"268268};269269270270/*271271- * Definitions for RCU-tasks perf testing.271271+ * Definitions for RCU-tasks scalability testing.272272 */273273274274-static int tasks_perf_read_lock(void)274274+static int tasks_scale_read_lock(void)275275{276276 return 0;277277}278278279279-static void tasks_perf_read_unlock(int idx)279279+static void tasks_scale_read_unlock(int idx)280280{281281}282282283283-static struct rcu_perf_ops tasks_ops = {283283+static struct rcu_scale_ops tasks_ops = {284284 .ptype = RCU_TASKS_FLAVOR,285285- .init = rcu_sync_perf_init,286286- .readlock = tasks_perf_read_lock,287287- .readunlock = tasks_perf_read_unlock,285285+ .init = rcu_sync_scale_init,286286+ .readlock = tasks_scale_read_lock,287287+ .readunlock = tasks_scale_read_unlock,288288 .get_gp_seq = rcu_no_completed,289289 .gp_diff = rcu_seq_diff,290290 .async = call_rcu_tasks,···294294 .name = "tasks"295295};296296297297-static unsigned long rcuperf_seq_diff(unsigned long new, unsigned long old)297297+static unsigned long rcuscale_seq_diff(unsigned long new, unsigned long old)298298{299299 if (!cur_ops->gp_diff)300300 return new - old;···302302}303303304304/*305305- * If performance tests complete, wait for shutdown to commence.305305+ * If scalability tests complete, wait for shutdown to commence.306306 */307307-static void rcu_perf_wait_shutdown(void)307307+static void rcu_scale_wait_shutdown(void)308308{309309 cond_resched_tasks_rcu_qs();310310- if (atomic_read(&n_rcu_perf_writer_finished) < nrealwriters)310310+ if (atomic_read(&n_rcu_scale_writer_finished) < nrealwriters)311311 return;312312 while (!torture_must_stop())313313 schedule_timeout_uninterruptible(1);314314}315315316316/*317317- * RCU perf reader kthread. Repeatedly does empty RCU read-side critical318318- * section, minimizing update-side interference. However, the point of319319- * this test is not to evaluate reader performance, but instead to serve320320- * as a test load for update-side performance testing.317317+ * RCU scalability reader kthread. Repeatedly does empty RCU read-side318318+ * critical section, minimizing update-side interference. However, the319319+ * point of this test is not to evaluate reader scalability, but instead320320+ * to serve as a test load for update-side scalability testing.321321 */322322static int323323-rcu_perf_reader(void *arg)323323+rcu_scale_reader(void *arg)324324{325325 unsigned long flags;326326 int idx;327327 long me = (long)arg;328328329329- VERBOSE_PERFOUT_STRING("rcu_perf_reader task started");329329+ VERBOSE_SCALEOUT_STRING("rcu_scale_reader task started");330330 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));331331 set_user_nice(current, MAX_NICE);332332- atomic_inc(&n_rcu_perf_reader_started);332332+ atomic_inc(&n_rcu_scale_reader_started);333333334334 do {335335 local_irq_save(flags);336336 idx = cur_ops->readlock();337337 cur_ops->readunlock(idx);338338 local_irq_restore(flags);339339- rcu_perf_wait_shutdown();339339+ rcu_scale_wait_shutdown();340340 } while (!torture_must_stop());341341- torture_kthread_stopping("rcu_perf_reader");341341+ torture_kthread_stopping("rcu_scale_reader");342342 return 0;343343}344344345345/*346346- * Callback function for asynchronous grace periods from rcu_perf_writer().346346+ * Callback function for asynchronous grace periods from rcu_scale_writer().347347 */348348-static void rcu_perf_async_cb(struct rcu_head *rhp)348348+static void rcu_scale_async_cb(struct rcu_head *rhp)349349{350350 atomic_dec(this_cpu_ptr(&n_async_inflight));351351 kfree(rhp);352352}353353354354/*355355- * RCU perf writer kthread. Repeatedly does a grace period.355355+ * RCU scale writer kthread. Repeatedly does a grace period.356356 */357357static int358358-rcu_perf_writer(void *arg)358358+rcu_scale_writer(void *arg)359359{360360 int i = 0;361361 int i_max;···366366 u64 *wdp;367367 u64 *wdpp = writer_durations[me];368368369369- VERBOSE_PERFOUT_STRING("rcu_perf_writer task started");369369+ VERBOSE_SCALEOUT_STRING("rcu_scale_writer task started");370370 WARN_ON(!wdpp);371371 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));372372 sched_set_fifo_low(current);···383383 schedule_timeout_uninterruptible(1);384384385385 t = ktime_get_mono_fast_ns();386386- if (atomic_inc_return(&n_rcu_perf_writer_started) >= nrealwriters) {387387- t_rcu_perf_writer_started = t;386386+ if (atomic_inc_return(&n_rcu_scale_writer_started) >= nrealwriters) {387387+ t_rcu_scale_writer_started = t;388388 if (gp_exp) {389389 b_rcu_gp_test_started =390390 cur_ops->exp_completed() / 2;···404404 rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);405405 if (rhp && atomic_read(this_cpu_ptr(&n_async_inflight)) < gp_async_max) {406406 atomic_inc(this_cpu_ptr(&n_async_inflight));407407- cur_ops->async(rhp, rcu_perf_async_cb);407407+ cur_ops->async(rhp, rcu_scale_async_cb);408408 rhp = NULL;409409 } else if (!kthread_should_stop()) {410410 cur_ops->gp_barrier();···421421 *wdp = t - *wdp;422422 i_max = i;423423 if (!started &&424424- atomic_read(&n_rcu_perf_writer_started) >= nrealwriters)424424+ atomic_read(&n_rcu_scale_writer_started) >= nrealwriters)425425 started = true;426426 if (!done && i >= MIN_MEAS) {427427 done = true;428428 sched_set_normal(current, 0);429429- pr_alert("%s%s rcu_perf_writer %ld has %d measurements\n",430430- perf_type, PERF_FLAG, me, MIN_MEAS);431431- if (atomic_inc_return(&n_rcu_perf_writer_finished) >=429429+ pr_alert("%s%s rcu_scale_writer %ld has %d measurements\n",430430+ scale_type, SCALE_FLAG, me, MIN_MEAS);431431+ if (atomic_inc_return(&n_rcu_scale_writer_finished) >=432432 nrealwriters) {433433 schedule_timeout_interruptible(10);434434 rcu_ftrace_dump(DUMP_ALL);435435- PERFOUT_STRING("Test complete");436436- t_rcu_perf_writer_finished = t;435435+ SCALEOUT_STRING("Test complete");436436+ t_rcu_scale_writer_finished = t;437437 if (gp_exp) {438438 b_rcu_gp_test_finished =439439 cur_ops->exp_completed() / 2;···448448 }449449 }450450 if (done && !alldone &&451451- atomic_read(&n_rcu_perf_writer_finished) >= nrealwriters)451451+ atomic_read(&n_rcu_scale_writer_finished) >= nrealwriters)452452 alldone = true;453453 if (started && !alldone && i < MAX_MEAS - 1)454454 i++;455455- rcu_perf_wait_shutdown();455455+ rcu_scale_wait_shutdown();456456 } while (!torture_must_stop());457457 if (gp_async) {458458 cur_ops->gp_barrier();459459 }460460 writer_n_durations[me] = i_max;461461- torture_kthread_stopping("rcu_perf_writer");461461+ torture_kthread_stopping("rcu_scale_writer");462462 return 0;463463}464464465465static void466466-rcu_perf_print_module_parms(struct rcu_perf_ops *cur_ops, const char *tag)466466+rcu_scale_print_module_parms(struct rcu_scale_ops *cur_ops, const char *tag)467467{468468- pr_alert("%s" PERF_FLAG468468+ pr_alert("%s" SCALE_FLAG469469 "--- %s: nreaders=%d nwriters=%d verbose=%d shutdown=%d\n",470470- perf_type, tag, nrealreaders, nrealwriters, verbose, shutdown);470470+ scale_type, tag, nrealreaders, nrealwriters, verbose, shutdown);471471}472472473473static void474474-rcu_perf_cleanup(void)474474+rcu_scale_cleanup(void)475475{476476 int i;477477 int j;···484484 * during the mid-boot phase, so have to wait till the end.485485 */486486 if (rcu_gp_is_expedited() && !rcu_gp_is_normal() && !gp_exp)487487- VERBOSE_PERFOUT_ERRSTRING("All grace periods expedited, no normal ones to measure!");487487+ VERBOSE_SCALEOUT_ERRSTRING("All grace periods expedited, no normal ones to measure!");488488 if (rcu_gp_is_normal() && gp_exp)489489- VERBOSE_PERFOUT_ERRSTRING("All grace periods normal, no expedited ones to measure!");489489+ VERBOSE_SCALEOUT_ERRSTRING("All grace periods normal, no expedited ones to measure!");490490 if (gp_exp && gp_async)491491- VERBOSE_PERFOUT_ERRSTRING("No expedited async GPs, so went with async!");491491+ VERBOSE_SCALEOUT_ERRSTRING("No expedited async GPs, so went with async!");492492493493 if (torture_cleanup_begin())494494 return;···499499500500 if (reader_tasks) {501501 for (i = 0; i < nrealreaders; i++)502502- torture_stop_kthread(rcu_perf_reader,502502+ torture_stop_kthread(rcu_scale_reader,503503 reader_tasks[i]);504504 kfree(reader_tasks);505505 }506506507507 if (writer_tasks) {508508 for (i = 0; i < nrealwriters; i++) {509509- torture_stop_kthread(rcu_perf_writer,509509+ torture_stop_kthread(rcu_scale_writer,510510 writer_tasks[i]);511511 if (!writer_n_durations)512512 continue;513513 j = writer_n_durations[i];514514 pr_alert("%s%s writer %d gps: %d\n",515515- perf_type, PERF_FLAG, i, j);515515+ scale_type, SCALE_FLAG, i, j);516516 ngps += j;517517 }518518 pr_alert("%s%s start: %llu end: %llu duration: %llu gps: %d batches: %ld\n",519519- perf_type, PERF_FLAG,520520- t_rcu_perf_writer_started, t_rcu_perf_writer_finished,521521- t_rcu_perf_writer_finished -522522- t_rcu_perf_writer_started,519519+ scale_type, SCALE_FLAG,520520+ t_rcu_scale_writer_started, t_rcu_scale_writer_finished,521521+ t_rcu_scale_writer_finished -522522+ t_rcu_scale_writer_started,523523 ngps,524524- rcuperf_seq_diff(b_rcu_gp_test_finished,525525- b_rcu_gp_test_started));524524+ rcuscale_seq_diff(b_rcu_gp_test_finished,525525+ b_rcu_gp_test_started));526526 for (i = 0; i < nrealwriters; i++) {527527 if (!writer_durations)528528 break;···534534 for (j = 0; j <= writer_n_durations[i]; j++) {535535 wdp = &wdpp[j];536536 pr_alert("%s%s %4d writer-duration: %5d %llu\n",537537- perf_type, PERF_FLAG,537537+ scale_type, SCALE_FLAG,538538 i, j, *wdp);539539 if (j % 100 == 0)540540 schedule_timeout_uninterruptible(1);···573573}574574575575/*576576- * RCU perf shutdown kthread. Just waits to be awakened, then shuts576576+ * RCU scalability shutdown kthread. Just waits to be awakened, then shuts577577 * down system.578578 */579579static int580580-rcu_perf_shutdown(void *arg)580580+rcu_scale_shutdown(void *arg)581581{582582 wait_event(shutdown_wq,583583- atomic_read(&n_rcu_perf_writer_finished) >= nrealwriters);583583+ atomic_read(&n_rcu_scale_writer_finished) >= nrealwriters);584584 smp_mb(); /* Wake before output. */585585- rcu_perf_cleanup();585585+ rcu_scale_cleanup();586586 kernel_power_off();587587 return -EINVAL;588588}589589590590/*591591- * kfree_rcu() performance tests: Start a kfree_rcu() loop on all CPUs for number591591+ * kfree_rcu() scalability tests: Start a kfree_rcu() loop on all CPUs for number592592 * of iterations and measure total time and number of GP for all iterations to complete.593593 */594594···598598599599static struct task_struct **kfree_reader_tasks;600600static int kfree_nrealthreads;601601-static atomic_t n_kfree_perf_thread_started;602602-static atomic_t n_kfree_perf_thread_ended;601601+static atomic_t n_kfree_scale_thread_started;602602+static atomic_t n_kfree_scale_thread_ended;603603604604struct kfree_obj {605605 char kfree_obj[8];···607607};608608609609static int610610-kfree_perf_thread(void *arg)610610+kfree_scale_thread(void *arg)611611{612612 int i, loop = 0;613613 long me = (long)arg;···615615 u64 start_time, end_time;616616 long long mem_begin, mem_during = 0;617617618618- VERBOSE_PERFOUT_STRING("kfree_perf_thread task started");618618+ VERBOSE_SCALEOUT_STRING("kfree_scale_thread task started");619619 set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));620620 set_user_nice(current, MAX_NICE);621621622622 start_time = ktime_get_mono_fast_ns();623623624624- if (atomic_inc_return(&n_kfree_perf_thread_started) >= kfree_nrealthreads) {624624+ if (atomic_inc_return(&n_kfree_scale_thread_started) >= kfree_nrealthreads) {625625 if (gp_exp)626626 b_rcu_gp_test_started = cur_ops->exp_completed() / 2;627627 else···646646 cond_resched();647647 } while (!torture_must_stop() && ++loop < kfree_loops);648648649649- if (atomic_inc_return(&n_kfree_perf_thread_ended) >= kfree_nrealthreads) {649649+ if (atomic_inc_return(&n_kfree_scale_thread_ended) >= kfree_nrealthreads) {650650 end_time = ktime_get_mono_fast_ns();651651652652 if (gp_exp)···656656657657 pr_alert("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld, memory footprint: %lldMB\n",658658 (unsigned long long)(end_time - start_time), kfree_loops,659659- rcuperf_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started),659659+ rcuscale_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started),660660 (mem_begin - mem_during) >> (20 - PAGE_SHIFT));661661662662 if (shutdown) {···665665 }666666 }667667668668- torture_kthread_stopping("kfree_perf_thread");668668+ torture_kthread_stopping("kfree_scale_thread");669669 return 0;670670}671671672672static void673673-kfree_perf_cleanup(void)673673+kfree_scale_cleanup(void)674674{675675 int i;676676···679679680680 if (kfree_reader_tasks) {681681 for (i = 0; i < kfree_nrealthreads; i++)682682- torture_stop_kthread(kfree_perf_thread,682682+ torture_stop_kthread(kfree_scale_thread,683683 kfree_reader_tasks[i]);684684 kfree(kfree_reader_tasks);685685 }···691691 * shutdown kthread. Just waits to be awakened, then shuts down system.692692 */693693static int694694-kfree_perf_shutdown(void *arg)694694+kfree_scale_shutdown(void *arg)695695{696696 wait_event(shutdown_wq,697697- atomic_read(&n_kfree_perf_thread_ended) >= kfree_nrealthreads);697697+ atomic_read(&n_kfree_scale_thread_ended) >= kfree_nrealthreads);698698699699 smp_mb(); /* Wake before output. */700700701701- kfree_perf_cleanup();701701+ kfree_scale_cleanup();702702 kernel_power_off();703703 return -EINVAL;704704}705705706706static int __init707707-kfree_perf_init(void)707707+kfree_scale_init(void)708708{709709 long i;710710 int firsterr = 0;···713713 /* Start up the kthreads. */714714 if (shutdown) {715715 init_waitqueue_head(&shutdown_wq);716716- firsterr = torture_create_kthread(kfree_perf_shutdown, NULL,716716+ firsterr = torture_create_kthread(kfree_scale_shutdown, NULL,717717 shutdown_task);718718 if (firsterr)719719 goto unwind;···730730 }731731732732 for (i = 0; i < kfree_nrealthreads; i++) {733733- firsterr = torture_create_kthread(kfree_perf_thread, (void *)i,733733+ firsterr = torture_create_kthread(kfree_scale_thread, (void *)i,734734 kfree_reader_tasks[i]);735735 if (firsterr)736736 goto unwind;737737 }738738739739- while (atomic_read(&n_kfree_perf_thread_started) < kfree_nrealthreads)739739+ while (atomic_read(&n_kfree_scale_thread_started) < kfree_nrealthreads)740740 schedule_timeout_uninterruptible(1);741741742742 torture_init_end();···744744745745unwind:746746 torture_init_end();747747- kfree_perf_cleanup();747747+ kfree_scale_cleanup();748748 return firsterr;749749}750750751751static int __init752752-rcu_perf_init(void)752752+rcu_scale_init(void)753753{754754 long i;755755 int firsterr = 0;756756- static struct rcu_perf_ops *perf_ops[] = {756756+ static struct rcu_scale_ops *scale_ops[] = {757757 &rcu_ops, &srcu_ops, &srcud_ops, &tasks_ops,758758 };759759760760- if (!torture_init_begin(perf_type, verbose))760760+ if (!torture_init_begin(scale_type, verbose))761761 return -EBUSY;762762763763- /* Process args and tell the world that the perf'er is on the job. */764764- for (i = 0; i < ARRAY_SIZE(perf_ops); i++) {765765- cur_ops = perf_ops[i];766766- if (strcmp(perf_type, cur_ops->name) == 0)763763+ /* Process args and announce that the scalability'er is on the job. */764764+ for (i = 0; i < ARRAY_SIZE(scale_ops); i++) {765765+ cur_ops = scale_ops[i];766766+ if (strcmp(scale_type, cur_ops->name) == 0)767767 break;768768 }769769- if (i == ARRAY_SIZE(perf_ops)) {770770- pr_alert("rcu-perf: invalid perf type: \"%s\"\n", perf_type);771771- pr_alert("rcu-perf types:");772772- for (i = 0; i < ARRAY_SIZE(perf_ops); i++)773773- pr_cont(" %s", perf_ops[i]->name);769769+ if (i == ARRAY_SIZE(scale_ops)) {770770+ pr_alert("rcu-scale: invalid scale type: \"%s\"\n", scale_type);771771+ pr_alert("rcu-scale types:");772772+ for (i = 0; i < ARRAY_SIZE(scale_ops); i++)773773+ pr_cont(" %s", scale_ops[i]->name);774774 pr_cont("\n");775775- WARN_ON(!IS_MODULE(CONFIG_RCU_PERF_TEST));775775+ WARN_ON(!IS_MODULE(CONFIG_RCU_SCALE_TEST));776776 firsterr = -EINVAL;777777 cur_ops = NULL;778778 goto unwind;···781781 cur_ops->init();782782783783 if (kfree_rcu_test)784784- return kfree_perf_init();784784+ return kfree_scale_init();785785786786 nrealwriters = compute_real(nwriters);787787 nrealreaders = compute_real(nreaders);788788- atomic_set(&n_rcu_perf_reader_started, 0);789789- atomic_set(&n_rcu_perf_writer_started, 0);790790- atomic_set(&n_rcu_perf_writer_finished, 0);791791- rcu_perf_print_module_parms(cur_ops, "Start of test");788788+ atomic_set(&n_rcu_scale_reader_started, 0);789789+ atomic_set(&n_rcu_scale_writer_started, 0);790790+ atomic_set(&n_rcu_scale_writer_finished, 0);791791+ rcu_scale_print_module_parms(cur_ops, "Start of test");792792793793 /* Start up the kthreads. */794794795795 if (shutdown) {796796 init_waitqueue_head(&shutdown_wq);797797- firsterr = torture_create_kthread(rcu_perf_shutdown, NULL,797797+ firsterr = torture_create_kthread(rcu_scale_shutdown, NULL,798798 shutdown_task);799799 if (firsterr)800800 goto unwind;···803803 reader_tasks = kcalloc(nrealreaders, sizeof(reader_tasks[0]),804804 GFP_KERNEL);805805 if (reader_tasks == NULL) {806806- VERBOSE_PERFOUT_ERRSTRING("out of memory");806806+ VERBOSE_SCALEOUT_ERRSTRING("out of memory");807807 firsterr = -ENOMEM;808808 goto unwind;809809 }810810 for (i = 0; i < nrealreaders; i++) {811811- firsterr = torture_create_kthread(rcu_perf_reader, (void *)i,811811+ firsterr = torture_create_kthread(rcu_scale_reader, (void *)i,812812 reader_tasks[i]);813813 if (firsterr)814814 goto unwind;815815 }816816- while (atomic_read(&n_rcu_perf_reader_started) < nrealreaders)816816+ while (atomic_read(&n_rcu_scale_reader_started) < nrealreaders)817817 schedule_timeout_uninterruptible(1);818818 writer_tasks = kcalloc(nrealwriters, sizeof(reader_tasks[0]),819819 GFP_KERNEL);···823823 kcalloc(nrealwriters, sizeof(*writer_n_durations),824824 GFP_KERNEL);825825 if (!writer_tasks || !writer_durations || !writer_n_durations) {826826- VERBOSE_PERFOUT_ERRSTRING("out of memory");826826+ VERBOSE_SCALEOUT_ERRSTRING("out of memory");827827 firsterr = -ENOMEM;828828 goto unwind;829829 }···835835 firsterr = -ENOMEM;836836 goto unwind;837837 }838838- firsterr = torture_create_kthread(rcu_perf_writer, (void *)i,838838+ firsterr = torture_create_kthread(rcu_scale_writer, (void *)i,839839 writer_tasks[i]);840840 if (firsterr)841841 goto unwind;···845845846846unwind:847847 torture_init_end();848848- rcu_perf_cleanup();848848+ rcu_scale_cleanup();849849 return firsterr;850850}851851852852-module_init(rcu_perf_init);853853-module_exit(rcu_perf_cleanup);852852+module_init(rcu_scale_init);853853+module_exit(rcu_scale_cleanup);
+575
kernel/scftorture.c
···11+// SPDX-License-Identifier: GPL-2.0+22+//33+// Torture test for smp_call_function() and friends.44+//55+// Copyright (C) Facebook, 2020.66+//77+// Author: Paul E. McKenney <paulmck@kernel.org>88+99+#define pr_fmt(fmt) fmt1010+1111+#include <linux/atomic.h>1212+#include <linux/bitops.h>1313+#include <linux/completion.h>1414+#include <linux/cpu.h>1515+#include <linux/delay.h>1616+#include <linux/err.h>1717+#include <linux/init.h>1818+#include <linux/interrupt.h>1919+#include <linux/kthread.h>2020+#include <linux/kernel.h>2121+#include <linux/mm.h>2222+#include <linux/module.h>2323+#include <linux/moduleparam.h>2424+#include <linux/notifier.h>2525+#include <linux/percpu.h>2626+#include <linux/rcupdate.h>2727+#include <linux/rcupdate_trace.h>2828+#include <linux/reboot.h>2929+#include <linux/sched.h>3030+#include <linux/spinlock.h>3131+#include <linux/smp.h>3232+#include <linux/stat.h>3333+#include <linux/srcu.h>3434+#include <linux/slab.h>3535+#include <linux/torture.h>3636+#include <linux/types.h>3737+3838+#define SCFTORT_STRING "scftorture"3939+#define SCFTORT_FLAG SCFTORT_STRING ": "4040+4141+#define SCFTORTOUT(s, x...) \4242+ pr_alert(SCFTORT_FLAG s, ## x)4343+4444+#define VERBOSE_SCFTORTOUT(s, x...) \4545+ do { if (verbose) pr_alert(SCFTORT_FLAG s, ## x); } while (0)4646+4747+#define VERBOSE_SCFTORTOUT_ERRSTRING(s, x...) \4848+ do { if (verbose) pr_alert(SCFTORT_FLAG "!!! " s, ## x); } while (0)4949+5050+MODULE_LICENSE("GPL");5151+MODULE_AUTHOR("Paul E. McKenney <paulmck@kernel.org>");5252+5353+// Wait until there are multiple CPUs before starting test.5454+torture_param(int, holdoff, IS_BUILTIN(CONFIG_SCF_TORTURE_TEST) ? 10 : 0,5555+ "Holdoff time before test start (s)");5656+torture_param(int, longwait, 0, "Include ridiculously long waits? (seconds)");5757+torture_param(int, nthreads, -1, "# threads, defaults to -1 for all CPUs.");5858+torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");5959+torture_param(int, onoff_interval, 0, "Time between CPU hotplugs (s), 0=disable");6060+torture_param(int, shutdown_secs, 0, "Shutdown time (ms), <= zero to disable.");6161+torture_param(int, stat_interval, 60, "Number of seconds between stats printk()s.");6262+torture_param(int, stutter_cpus, 5, "Number of jiffies to change CPUs under test, 0=disable");6363+torture_param(bool, use_cpus_read_lock, 0, "Use cpus_read_lock() to exclude CPU hotplug.");6464+torture_param(int, verbose, 0, "Enable verbose debugging printk()s");6565+torture_param(int, weight_single, -1, "Testing weight for single-CPU no-wait operations.");6666+torture_param(int, weight_single_wait, -1, "Testing weight for single-CPU operations.");6767+torture_param(int, weight_many, -1, "Testing weight for multi-CPU no-wait operations.");6868+torture_param(int, weight_many_wait, -1, "Testing weight for multi-CPU operations.");6969+torture_param(int, weight_all, -1, "Testing weight for all-CPU no-wait operations.");7070+torture_param(int, weight_all_wait, -1, "Testing weight for all-CPU operations.");7171+7272+char *torture_type = "";7373+7474+#ifdef MODULE7575+# define SCFTORT_SHUTDOWN 07676+#else7777+# define SCFTORT_SHUTDOWN 17878+#endif7979+8080+torture_param(bool, shutdown, SCFTORT_SHUTDOWN, "Shutdown at end of torture test.");8181+8282+struct scf_statistics {8383+ struct task_struct *task;8484+ int cpu;8585+ long long n_single;8686+ long long n_single_ofl;8787+ long long n_single_wait;8888+ long long n_single_wait_ofl;8989+ long long n_many;9090+ long long n_many_wait;9191+ long long n_all;9292+ long long n_all_wait;9393+};9494+9595+static struct scf_statistics *scf_stats_p;9696+static struct task_struct *scf_torture_stats_task;9797+static DEFINE_PER_CPU(long long, scf_invoked_count);9898+9999+// Data for random primitive selection100100+#define SCF_PRIM_SINGLE 0101101+#define SCF_PRIM_MANY 1102102+#define SCF_PRIM_ALL 2103103+#define SCF_NPRIMS (2 * 3) // Need wait and no-wait versions of each.104104+105105+static char *scf_prim_name[] = {106106+ "smp_call_function_single",107107+ "smp_call_function_many",108108+ "smp_call_function",109109+};110110+111111+struct scf_selector {112112+ unsigned long scfs_weight;113113+ int scfs_prim;114114+ bool scfs_wait;115115+};116116+static struct scf_selector scf_sel_array[SCF_NPRIMS];117117+static int scf_sel_array_len;118118+static unsigned long scf_sel_totweight;119119+120120+// Communicate between caller and handler.121121+struct scf_check {122122+ bool scfc_in;123123+ bool scfc_out;124124+ int scfc_cpu; // -1 for not _single().125125+ bool scfc_wait;126126+};127127+128128+// Use to wait for all threads to start.129129+static atomic_t n_started;130130+static atomic_t n_errs;131131+static atomic_t n_mb_in_errs;132132+static atomic_t n_mb_out_errs;133133+static atomic_t n_alloc_errs;134134+static bool scfdone;135135+static char *bangstr = "";136136+137137+static DEFINE_TORTURE_RANDOM_PERCPU(scf_torture_rand);138138+139139+// Print torture statistics. Caller must ensure serialization.140140+static void scf_torture_stats_print(void)141141+{142142+ int cpu;143143+ int i;144144+ long long invoked_count = 0;145145+ bool isdone = READ_ONCE(scfdone);146146+ struct scf_statistics scfs = {};147147+148148+ for_each_possible_cpu(cpu)149149+ invoked_count += data_race(per_cpu(scf_invoked_count, cpu));150150+ for (i = 0; i < nthreads; i++) {151151+ scfs.n_single += scf_stats_p[i].n_single;152152+ scfs.n_single_ofl += scf_stats_p[i].n_single_ofl;153153+ scfs.n_single_wait += scf_stats_p[i].n_single_wait;154154+ scfs.n_single_wait_ofl += scf_stats_p[i].n_single_wait_ofl;155155+ scfs.n_many += scf_stats_p[i].n_many;156156+ scfs.n_many_wait += scf_stats_p[i].n_many_wait;157157+ scfs.n_all += scf_stats_p[i].n_all;158158+ scfs.n_all_wait += scf_stats_p[i].n_all_wait;159159+ }160160+ if (atomic_read(&n_errs) || atomic_read(&n_mb_in_errs) ||161161+ atomic_read(&n_mb_out_errs) || atomic_read(&n_alloc_errs))162162+ bangstr = "!!! ";163163+ pr_alert("%s %sscf_invoked_count %s: %lld single: %lld/%lld single_ofl: %lld/%lld many: %lld/%lld all: %lld/%lld ",164164+ SCFTORT_FLAG, bangstr, isdone ? "VER" : "ver", invoked_count,165165+ scfs.n_single, scfs.n_single_wait, scfs.n_single_ofl, scfs.n_single_wait_ofl,166166+ scfs.n_many, scfs.n_many_wait, scfs.n_all, scfs.n_all_wait);167167+ torture_onoff_stats();168168+ pr_cont("ste: %d stnmie: %d stnmoe: %d staf: %d\n", atomic_read(&n_errs),169169+ atomic_read(&n_mb_in_errs), atomic_read(&n_mb_out_errs),170170+ atomic_read(&n_alloc_errs));171171+}172172+173173+// Periodically prints torture statistics, if periodic statistics printing174174+// was specified via the stat_interval module parameter.175175+static int176176+scf_torture_stats(void *arg)177177+{178178+ VERBOSE_TOROUT_STRING("scf_torture_stats task started");179179+ do {180180+ schedule_timeout_interruptible(stat_interval * HZ);181181+ scf_torture_stats_print();182182+ torture_shutdown_absorb("scf_torture_stats");183183+ } while (!torture_must_stop());184184+ torture_kthread_stopping("scf_torture_stats");185185+ return 0;186186+}187187+188188+// Add a primitive to the scf_sel_array[].189189+static void scf_sel_add(unsigned long weight, int prim, bool wait)190190+{191191+ struct scf_selector *scfsp = &scf_sel_array[scf_sel_array_len];192192+193193+ // If no weight, if array would overflow, if computing three-place194194+ // percentages would overflow, or if the scf_prim_name[] array would195195+ // overflow, don't bother. In the last three two cases, complain.196196+ if (!weight ||197197+ WARN_ON_ONCE(scf_sel_array_len >= ARRAY_SIZE(scf_sel_array)) ||198198+ WARN_ON_ONCE(0 - 100000 * weight <= 100000 * scf_sel_totweight) ||199199+ WARN_ON_ONCE(prim >= ARRAY_SIZE(scf_prim_name)))200200+ return;201201+ scf_sel_totweight += weight;202202+ scfsp->scfs_weight = scf_sel_totweight;203203+ scfsp->scfs_prim = prim;204204+ scfsp->scfs_wait = wait;205205+ scf_sel_array_len++;206206+}207207+208208+// Dump out weighting percentages for scf_prim_name[] array.209209+static void scf_sel_dump(void)210210+{211211+ int i;212212+ unsigned long oldw = 0;213213+ struct scf_selector *scfsp;214214+ unsigned long w;215215+216216+ for (i = 0; i < scf_sel_array_len; i++) {217217+ scfsp = &scf_sel_array[i];218218+ w = (scfsp->scfs_weight - oldw) * 100000 / scf_sel_totweight;219219+ pr_info("%s: %3lu.%03lu %s(%s)\n", __func__, w / 1000, w % 1000,220220+ scf_prim_name[scfsp->scfs_prim],221221+ scfsp->scfs_wait ? "wait" : "nowait");222222+ oldw = scfsp->scfs_weight;223223+ }224224+}225225+226226+// Randomly pick a primitive and wait/nowait, based on weightings.227227+static struct scf_selector *scf_sel_rand(struct torture_random_state *trsp)228228+{229229+ int i;230230+ unsigned long w = torture_random(trsp) % (scf_sel_totweight + 1);231231+232232+ for (i = 0; i < scf_sel_array_len; i++)233233+ if (scf_sel_array[i].scfs_weight >= w)234234+ return &scf_sel_array[i];235235+ WARN_ON_ONCE(1);236236+ return &scf_sel_array[0];237237+}238238+239239+// Update statistics and occasionally burn up mass quantities of CPU time,240240+// if told to do so via scftorture.longwait. Otherwise, occasionally burn241241+// a little bit.242242+static void scf_handler(void *scfc_in)243243+{244244+ int i;245245+ int j;246246+ unsigned long r = torture_random(this_cpu_ptr(&scf_torture_rand));247247+ struct scf_check *scfcp = scfc_in;248248+249249+ if (likely(scfcp)) {250250+ WRITE_ONCE(scfcp->scfc_out, false); // For multiple receivers.251251+ if (WARN_ON_ONCE(unlikely(!READ_ONCE(scfcp->scfc_in))))252252+ atomic_inc(&n_mb_in_errs);253253+ }254254+ this_cpu_inc(scf_invoked_count);255255+ if (longwait <= 0) {256256+ if (!(r & 0xffc0))257257+ udelay(r & 0x3f);258258+ goto out;259259+ }260260+ if (r & 0xfff)261261+ goto out;262262+ r = (r >> 12);263263+ if (longwait <= 0) {264264+ udelay((r & 0xff) + 1);265265+ goto out;266266+ }267267+ r = r % longwait + 1;268268+ for (i = 0; i < r; i++) {269269+ for (j = 0; j < 1000; j++) {270270+ udelay(1000);271271+ cpu_relax();272272+ }273273+ }274274+out:275275+ if (unlikely(!scfcp))276276+ return;277277+ if (scfcp->scfc_wait)278278+ WRITE_ONCE(scfcp->scfc_out, true);279279+ else280280+ kfree(scfcp);281281+}282282+283283+// As above, but check for correct CPU.284284+static void scf_handler_1(void *scfc_in)285285+{286286+ struct scf_check *scfcp = scfc_in;287287+288288+ if (likely(scfcp) && WARN_ONCE(smp_processor_id() != scfcp->scfc_cpu, "%s: Wanted CPU %d got CPU %d\n", __func__, scfcp->scfc_cpu, smp_processor_id())) {289289+ atomic_inc(&n_errs);290290+ }291291+ scf_handler(scfcp);292292+}293293+294294+// Randomly do an smp_call_function*() invocation.295295+static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_random_state *trsp)296296+{297297+ uintptr_t cpu;298298+ int ret = 0;299299+ struct scf_check *scfcp = NULL;300300+ struct scf_selector *scfsp = scf_sel_rand(trsp);301301+302302+ if (use_cpus_read_lock)303303+ cpus_read_lock();304304+ else305305+ preempt_disable();306306+ if (scfsp->scfs_prim == SCF_PRIM_SINGLE || scfsp->scfs_wait) {307307+ scfcp = kmalloc(sizeof(*scfcp), GFP_ATOMIC);308308+ if (WARN_ON_ONCE(!scfcp)) {309309+ atomic_inc(&n_alloc_errs);310310+ } else {311311+ scfcp->scfc_cpu = -1;312312+ scfcp->scfc_wait = scfsp->scfs_wait;313313+ scfcp->scfc_out = false;314314+ }315315+ }316316+ switch (scfsp->scfs_prim) {317317+ case SCF_PRIM_SINGLE:318318+ cpu = torture_random(trsp) % nr_cpu_ids;319319+ if (scfsp->scfs_wait)320320+ scfp->n_single_wait++;321321+ else322322+ scfp->n_single++;323323+ if (scfcp) {324324+ scfcp->scfc_cpu = cpu;325325+ barrier(); // Prevent race-reduction compiler optimizations.326326+ scfcp->scfc_in = true;327327+ }328328+ ret = smp_call_function_single(cpu, scf_handler_1, (void *)scfcp, scfsp->scfs_wait);329329+ if (ret) {330330+ if (scfsp->scfs_wait)331331+ scfp->n_single_wait_ofl++;332332+ else333333+ scfp->n_single_ofl++;334334+ kfree(scfcp);335335+ scfcp = NULL;336336+ }337337+ break;338338+ case SCF_PRIM_MANY:339339+ if (scfsp->scfs_wait)340340+ scfp->n_many_wait++;341341+ else342342+ scfp->n_many++;343343+ if (scfcp) {344344+ barrier(); // Prevent race-reduction compiler optimizations.345345+ scfcp->scfc_in = true;346346+ }347347+ smp_call_function_many(cpu_online_mask, scf_handler, scfcp, scfsp->scfs_wait);348348+ break;349349+ case SCF_PRIM_ALL:350350+ if (scfsp->scfs_wait)351351+ scfp->n_all_wait++;352352+ else353353+ scfp->n_all++;354354+ if (scfcp) {355355+ barrier(); // Prevent race-reduction compiler optimizations.356356+ scfcp->scfc_in = true;357357+ }358358+ smp_call_function(scf_handler, scfcp, scfsp->scfs_wait);359359+ break;360360+ default:361361+ WARN_ON_ONCE(1);362362+ if (scfcp)363363+ scfcp->scfc_out = true;364364+ }365365+ if (scfcp && scfsp->scfs_wait) {366366+ if (WARN_ON_ONCE((num_online_cpus() > 1 || scfsp->scfs_prim == SCF_PRIM_SINGLE) &&367367+ !scfcp->scfc_out))368368+ atomic_inc(&n_mb_out_errs); // Leak rather than trash!369369+ else370370+ kfree(scfcp);371371+ barrier(); // Prevent race-reduction compiler optimizations.372372+ }373373+ if (use_cpus_read_lock)374374+ cpus_read_unlock();375375+ else376376+ preempt_enable();377377+ if (!(torture_random(trsp) & 0xfff))378378+ schedule_timeout_uninterruptible(1);379379+}380380+381381+// SCF test kthread. Repeatedly does calls to members of the382382+// smp_call_function() family of functions.383383+static int scftorture_invoker(void *arg)384384+{385385+ int cpu;386386+ DEFINE_TORTURE_RANDOM(rand);387387+ struct scf_statistics *scfp = (struct scf_statistics *)arg;388388+ bool was_offline = false;389389+390390+ VERBOSE_SCFTORTOUT("scftorture_invoker %d: task started", scfp->cpu);391391+ cpu = scfp->cpu % nr_cpu_ids;392392+ set_cpus_allowed_ptr(current, cpumask_of(cpu));393393+ set_user_nice(current, MAX_NICE);394394+ if (holdoff)395395+ schedule_timeout_interruptible(holdoff * HZ);396396+397397+ VERBOSE_SCFTORTOUT("scftorture_invoker %d: Waiting for all SCF torturers from cpu %d", scfp->cpu, smp_processor_id());398398+399399+ // Make sure that the CPU is affinitized appropriately during testing.400400+ WARN_ON_ONCE(smp_processor_id() != scfp->cpu);401401+402402+ if (!atomic_dec_return(&n_started))403403+ while (atomic_read_acquire(&n_started)) {404404+ if (torture_must_stop()) {405405+ VERBOSE_SCFTORTOUT("scftorture_invoker %d ended before starting", scfp->cpu);406406+ goto end;407407+ }408408+ schedule_timeout_uninterruptible(1);409409+ }410410+411411+ VERBOSE_SCFTORTOUT("scftorture_invoker %d started", scfp->cpu);412412+413413+ do {414414+ scftorture_invoke_one(scfp, &rand);415415+ while (cpu_is_offline(cpu) && !torture_must_stop()) {416416+ schedule_timeout_interruptible(HZ / 5);417417+ was_offline = true;418418+ }419419+ if (was_offline) {420420+ set_cpus_allowed_ptr(current, cpumask_of(cpu));421421+ was_offline = false;422422+ }423423+ cond_resched();424424+ } while (!torture_must_stop());425425+426426+ VERBOSE_SCFTORTOUT("scftorture_invoker %d ended", scfp->cpu);427427+end:428428+ torture_kthread_stopping("scftorture_invoker");429429+ return 0;430430+}431431+432432+static void433433+scftorture_print_module_parms(const char *tag)434434+{435435+ pr_alert(SCFTORT_FLAG436436+ "--- %s: verbose=%d holdoff=%d longwait=%d nthreads=%d onoff_holdoff=%d onoff_interval=%d shutdown_secs=%d stat_interval=%d stutter_cpus=%d use_cpus_read_lock=%d, weight_single=%d, weight_single_wait=%d, weight_many=%d, weight_many_wait=%d, weight_all=%d, weight_all_wait=%d\n", tag,437437+ verbose, holdoff, longwait, nthreads, onoff_holdoff, onoff_interval, shutdown, stat_interval, stutter_cpus, use_cpus_read_lock, weight_single, weight_single_wait, weight_many, weight_many_wait, weight_all, weight_all_wait);438438+}439439+440440+static void scf_cleanup_handler(void *unused)441441+{442442+}443443+444444+static void scf_torture_cleanup(void)445445+{446446+ int i;447447+448448+ if (torture_cleanup_begin())449449+ return;450450+451451+ WRITE_ONCE(scfdone, true);452452+ if (nthreads)453453+ for (i = 0; i < nthreads; i++)454454+ torture_stop_kthread("scftorture_invoker", scf_stats_p[i].task);455455+ else456456+ goto end;457457+ smp_call_function(scf_cleanup_handler, NULL, 0);458458+ torture_stop_kthread(scf_torture_stats, scf_torture_stats_task);459459+ scf_torture_stats_print(); // -After- the stats thread is stopped!460460+ kfree(scf_stats_p); // -After- the last stats print has completed!461461+ scf_stats_p = NULL;462462+463463+ if (atomic_read(&n_errs) || atomic_read(&n_mb_in_errs) || atomic_read(&n_mb_out_errs))464464+ scftorture_print_module_parms("End of test: FAILURE");465465+ else if (torture_onoff_failures())466466+ scftorture_print_module_parms("End of test: LOCK_HOTPLUG");467467+ else468468+ scftorture_print_module_parms("End of test: SUCCESS");469469+470470+end:471471+ torture_cleanup_end();472472+}473473+474474+static int __init scf_torture_init(void)475475+{476476+ long i;477477+ int firsterr = 0;478478+ unsigned long weight_single1 = weight_single;479479+ unsigned long weight_single_wait1 = weight_single_wait;480480+ unsigned long weight_many1 = weight_many;481481+ unsigned long weight_many_wait1 = weight_many_wait;482482+ unsigned long weight_all1 = weight_all;483483+ unsigned long weight_all_wait1 = weight_all_wait;484484+485485+ if (!torture_init_begin(SCFTORT_STRING, verbose))486486+ return -EBUSY;487487+488488+ scftorture_print_module_parms("Start of test");489489+490490+ if (weight_single == -1 && weight_single_wait == -1 &&491491+ weight_many == -1 && weight_many_wait == -1 &&492492+ weight_all == -1 && weight_all_wait == -1) {493493+ weight_single1 = 2 * nr_cpu_ids;494494+ weight_single_wait1 = 2 * nr_cpu_ids;495495+ weight_many1 = 2;496496+ weight_many_wait1 = 2;497497+ weight_all1 = 1;498498+ weight_all_wait1 = 1;499499+ } else {500500+ if (weight_single == -1)501501+ weight_single1 = 0;502502+ if (weight_single_wait == -1)503503+ weight_single_wait1 = 0;504504+ if (weight_many == -1)505505+ weight_many1 = 0;506506+ if (weight_many_wait == -1)507507+ weight_many_wait1 = 0;508508+ if (weight_all == -1)509509+ weight_all1 = 0;510510+ if (weight_all_wait == -1)511511+ weight_all_wait1 = 0;512512+ }513513+ if (weight_single1 == 0 && weight_single_wait1 == 0 &&514514+ weight_many1 == 0 && weight_many_wait1 == 0 &&515515+ weight_all1 == 0 && weight_all_wait1 == 0) {516516+ VERBOSE_SCFTORTOUT_ERRSTRING("all zero weights makes no sense");517517+ firsterr = -EINVAL;518518+ goto unwind;519519+ }520520+ scf_sel_add(weight_single1, SCF_PRIM_SINGLE, false);521521+ scf_sel_add(weight_single_wait1, SCF_PRIM_SINGLE, true);522522+ scf_sel_add(weight_many1, SCF_PRIM_MANY, false);523523+ scf_sel_add(weight_many_wait1, SCF_PRIM_MANY, true);524524+ scf_sel_add(weight_all1, SCF_PRIM_ALL, false);525525+ scf_sel_add(weight_all_wait1, SCF_PRIM_ALL, true);526526+ scf_sel_dump();527527+528528+ if (onoff_interval > 0) {529529+ firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval, NULL);530530+ if (firsterr)531531+ goto unwind;532532+ }533533+ if (shutdown_secs > 0) {534534+ firsterr = torture_shutdown_init(shutdown_secs, scf_torture_cleanup);535535+ if (firsterr)536536+ goto unwind;537537+ }538538+539539+ // Worker tasks invoking smp_call_function().540540+ if (nthreads < 0)541541+ nthreads = num_online_cpus();542542+ scf_stats_p = kcalloc(nthreads, sizeof(scf_stats_p[0]), GFP_KERNEL);543543+ if (!scf_stats_p) {544544+ VERBOSE_SCFTORTOUT_ERRSTRING("out of memory");545545+ firsterr = -ENOMEM;546546+ goto unwind;547547+ }548548+549549+ VERBOSE_SCFTORTOUT("Starting %d smp_call_function() threads\n", nthreads);550550+551551+ atomic_set(&n_started, nthreads);552552+ for (i = 0; i < nthreads; i++) {553553+ scf_stats_p[i].cpu = i;554554+ firsterr = torture_create_kthread(scftorture_invoker, (void *)&scf_stats_p[i],555555+ scf_stats_p[i].task);556556+ if (firsterr)557557+ goto unwind;558558+ }559559+ if (stat_interval > 0) {560560+ firsterr = torture_create_kthread(scf_torture_stats, NULL, scf_torture_stats_task);561561+ if (firsterr)562562+ goto unwind;563563+ }564564+565565+ torture_init_end();566566+ return 0;567567+568568+unwind:569569+ torture_init_end();570570+ scf_torture_cleanup();571571+ return firsterr;572572+}573573+574574+module_init(scf_torture_init);575575+module_exit(scf_torture_cleanup);
+1-1
kernel/time/tick-sched.c
···927927928928 if (ratelimit < 10 &&929929 (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {930930- pr_warn("NOHZ: local_softirq_pending %02x\n",930930+ pr_warn("NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #%02x!!!\n",931931 (unsigned int) local_softirq_pending());932932 ratelimit++;933933 }
+10
lib/Kconfig.debug
···13671367 Say M if you want these self tests to build as a module.13681368 Say N if you are unsure.1369136913701370+config SCF_TORTURE_TEST13711371+ tristate "torture tests for smp_call_function*()"13721372+ depends on DEBUG_KERNEL13731373+ select TORTURE_TEST13741374+ help13751375+ This option provides a kernel module that runs torture tests13761376+ on the smp_call_function() family of primitives. The kernel13771377+ module may be built after the fact on the running kernel to13781378+ be tested, if desired.13791379+13701380endmenu # lock debugging1371138113721382config TRACE_IRQFLAGS
···11#!/bin/bash22# SPDX-License-Identifier: GPL-2.0+33#44-# Analyze a given results directory for rcuperf performance measurements,44+# Analyze a given results directory for rcuscale performance measurements,55# looking for ftrace data. Exits with 0 if data was found, analyzed, and66-# printed. Intended to be invoked from kvm-recheck-rcuperf.sh after66+# printed. Intended to be invoked from kvm-recheck-rcuscale.sh after77# argument checking.88#99-# Usage: kvm-recheck-rcuperf-ftrace.sh resdir99+# Usage: kvm-recheck-rcuscale-ftrace.sh resdir1010#1111# Copyright (C) IBM Corporation, 20161212#