On Wed, Oct 03, 2007 at 04:59:51PM -0400, Steven Rostedt wrote: > Paul, > > I ran your original preemption test of RCU torture, and after several > minutes, my preempt boost patch had one Preemption stall. I then > disabled preemption boosting, and ran the preempt torture again, and it > seemed to never stall. Something seemed strange, so I took a look. > > Looks like you have a single thread that will run at max prio that runs > for 10 secs and then sleeps again. This thread seems to only push rcu > readers around. But it doesn't seem to do much else. That is a good test > to see if RCU readers can handle being pushed around, but it doesn't > test preemption boosting. Looks like I shot myself in the foot by complaining about a bug... :-/ http://lkml.org/lkml/2007/6/10/234 With the bug, the readers weren't migrating, without it, they do. Good catch!!! Thank you!!! > To do that, I modified the test to create CPUS-1 preempt boost hogs (or > 1 if it is UP). But instead of putting it at max prio, I set it to the > lowest RT prio of 1. This way it's still at a higher priority than the > readers. I also switched the writers to run at 1+n where n increases for > every fake writer there is. > > Without preempt boosting, after a couple of minutes I had 83 preemption > stalls. When I turned my boosting back on, after several minutes (still > running as I type this) it has no preemption stalls. > > This seems to be a good test for RCU preemption boosting. I am testing it out against my earlier patchset, with some encouraging results -- I will incorporate into the next round of my mainline patchset. Some questions and comments below. > -- Steve > > PS. I got rid of your rcu_preeempt_task for rcu_preempt_tasks ;-) > > (No the above is _not_ a typo) :-/ > Signed-off-by: Steven Rostedt <rostedt@xxxxxxxxxxx> > > Index: linux-2.6.23-rc9-rt1/kernel/rcutorture.c > =================================================================== > --- linux-2.6.23-rc9-rt1.orig/kernel/rcutorture.c > +++ linux-2.6.23-rc9-rt1/kernel/rcutorture.c > @@ -54,6 +54,7 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck > > static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */ > static int nfakewriters = 4; /* # fake writer threads */ > +static int npreempthogs = -1; /* # preempt hogs to run (defaults to ncpus-1) or 1 */ > static int stat_interval; /* Interval between stats, in seconds. */ > /* Defaults to "only at end of test". */ > static int verbose; /* Print more debug info. */ > @@ -90,9 +91,11 @@ MODULE_PARM_DESC(torture_type, "Type of > static char printk_buf[4096]; > > static int nrealreaders; > +static int nrealpreempthogs; I made the above be a module parameter. This OK? > static struct task_struct *writer_task; > static struct task_struct **fakewriter_tasks; > static struct task_struct **reader_tasks; > +static struct task_struct **rcu_preempt_tasks; > static struct task_struct *stats_task; > static struct task_struct *shuffler_task; > > @@ -264,7 +267,6 @@ static void rcu_torture_deferred_free(st > call_rcu(&p->rtort_rcu, rcu_torture_cb); > } > > -static struct task_struct *rcu_preeempt_task; > static unsigned long rcu_torture_preempt_errors; > > static int rcu_torture_preempt(void *arg) > @@ -274,7 +276,7 @@ static int rcu_torture_preempt(void *arg > time_t gcstart; > struct sched_param sp; > > - sp.sched_priority = MAX_RT_PRIO - 1; > + sp.sched_priority = 1; > err = sched_setscheduler(current, SCHED_RR, &sp); > if (err != 0) > printk(KERN_ALERT "rcu_torture_preempt() priority err: %d\n", > @@ -297,24 +299,43 @@ static int rcu_torture_preempt(void *arg > static long rcu_preempt_start(void) > { > long retval = 0; > + int i; > > - rcu_preeempt_task = kthread_run(rcu_torture_preempt, NULL, > - "rcu_torture_preempt"); > - if (IS_ERR(rcu_preeempt_task)) { > - VERBOSE_PRINTK_ERRSTRING("Failed to create preempter"); > - retval = PTR_ERR(rcu_preeempt_task); > - rcu_preeempt_task = NULL; > + rcu_preempt_tasks = kzalloc(nrealpreempthogs * sizeof(rcu_preempt_tasks[0]), > + GFP_KERNEL); > + if (rcu_preempt_tasks == NULL) { > + VERBOSE_PRINTK_ERRSTRING("out of memory"); > + retval = -ENOMEM; > + goto out; > } > + > + for (i=0; i < nrealpreempthogs; i++) { > + rcu_preempt_tasks[i] = kthread_run(rcu_torture_preempt, NULL, > + "rcu_torture_preempt"); > + if (IS_ERR(rcu_preempt_tasks[i])) { > + VERBOSE_PRINTK_ERRSTRING("Failed to create preempter"); > + retval = PTR_ERR(rcu_preempt_tasks[i]); > + rcu_preempt_tasks[i] = NULL; > + break; > + } > + } > + out: > return retval; > } > > static void rcu_preempt_end(void) > { > - if (rcu_preeempt_task != NULL) { > - VERBOSE_PRINTK_STRING("Stopping rcu_preempt task"); > - kthread_stop(rcu_preeempt_task); > + int i; > + if (rcu_preempt_tasks) { > + for (i=0; i < nrealpreempthogs; i++) { > + if (rcu_preempt_tasks[i] != NULL) { > + VERBOSE_PRINTK_STRING("Stopping rcu_preempt task"); > + kthread_stop(rcu_preempt_tasks[i]); > + } > + rcu_preempt_tasks[i] = NULL; > + } > + kfree(rcu_preempt_tasks); > } > - rcu_preeempt_task = NULL; > } > > static int rcu_preempt_stats(char *page) > @@ -613,10 +634,20 @@ rcu_torture_writer(void *arg) > static int > rcu_torture_fakewriter(void *arg) > { > + struct sched_param sp; > + long id = (long) arg; > + int err; > DEFINE_RCU_RANDOM(rand); > > VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); > - set_user_nice(current, 19); > + /* > + * Set up at a higher prio than the readers. > + */ > + sp.sched_priority = 1 + id; > + err = sched_setscheduler(current, SCHED_RR, &sp); > + if (err != 0) > + printk(KERN_ALERT "rcu_torture_writer() priority err: %d\n", > + err); The idea here is to force inheritance, to force the writer to continue pushing grace periods even when the hogs are running, or both? > do { > schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); > @@ -849,9 +880,11 @@ rcu_torture_print_module_parms(char *tag > { > printk(KERN_ALERT "%s" TORTURE_FLAG > "--- %s: nreaders=%d nfakewriters=%d " > + "npreempthogs=%d " > "stat_interval=%d verbose=%d test_no_idle_hz=%d " > "shuffle_interval=%d preempt_torture=%d\n", > torture_type, tag, nrealreaders, nfakewriters, > + nrealpreempthogs, > stat_interval, verbose, test_no_idle_hz, shuffle_interval, > preempt_torture); > } > @@ -925,7 +958,7 @@ rcu_torture_cleanup(void) > static int __init > rcu_torture_init(void) > { > - int i; > + long i; > int cpu; > int firsterr = 0; > static struct rcu_torture_ops *torture_ops[] = > @@ -953,6 +986,12 @@ rcu_torture_init(void) > rcu_torture_print_module_parms("Start of test"); > fullstop = 0; > > + if (npreempthogs >= 0) > + nrealpreempthogs = npreempthogs; > + else > + nrealpreempthogs = num_online_cpus() == 1 ? 1 : > + num_online_cpus() - 1; OK -- the idea here is to leave at least one CPU to respond to keyboard and mouse? I end up with all the readers getting shoved to the left-over CPU. I am experimenting with ways of synchronizing the hogs and also allowing synchronized idle time... > + > /* Set up the freelist. */ > > INIT_LIST_HEAD(&rcu_torture_freelist); > @@ -1000,7 +1039,7 @@ rcu_torture_init(void) > } > for (i = 0; i < nfakewriters; i++) { > VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task"); > - fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL, > + fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, (void*)i, > "rcu_torture_fakewriter"); > if (IS_ERR(fakewriter_tasks[i])) { > firsterr = PTR_ERR(fakewriter_tasks[i]); > > > - > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ > - To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html