Real-Time Preemption, -RT-2.6.13-rc4-V0.7.52-01]
Subsystems (5)
Steven Rostedt
reviewerPATCH 1/1 Real-Time Preemption, -RT-2.6.13-rc4-V0.7.52-01]
Ingo,
This was my final version of the softlockup patch. Do you have any comments on it? I wasn't sure if you were waiting for any more debate on this patch or not.
Daniel,
Have any more debate on this patch? :-)
-- Steve
-------- Forwarded Message --------
From: Steven Rostedt <[email protected]>
To: Ingo Molnar <[email protected]>
Cc: [email protected], Daniel Walker <[email protected]>
Subject: Re: [patch] Real-Time Preemption, -RT-2.6.13-rc4-V0.7.52-01
Date: Wed, 03 Aug 2005 12:44:07 -0400
Ingo,
Doing some more tests on the patch, I found that I don't like the placement in sched.c of the touch_light_softlockup_watchdog. I figure that it may be better to put in into __schedule instead. This really shows where a task is taken off the run queue.
-- Steve
New patch: I've only tested this with the deadlock modules, and not with the kjournald case. I'll do that tonight when I'm no longer needing my computer for other tests.
kernel/irq/handle.c +8 -0
@@ -177,6 +177,14 @@*/ local_irq_save (flags);#endif +/* +* If the task is currently running in user mode, don't +* detect soft lockups. If CONFIG_DETECT_SOFTLOCKUP is not +* configured, this should be optimized out. +*/ +if (user_mode (regs)) +touch_light_softlockup_watchdog (); + kstat_this_cpu.irqs[irq]++;if (desc->status &IRQ_PER_CPU ) {irqreturn_t action_ret;
kernel/sched.c +1 -0
@@ -3209,6 +3209,7 @@else {if (prev->state ==TASK_UNINTERRUPTIBLE ) rq->nr_uninterruptible++; +touch_light_softlockup_watchdog ();deactivate_task (prev, rq); } }
kernel/softlockup.c +21 -19
@@ -3,6 +3,10 @@* * started by Ingo Molnar, (C) 2005, Red Hat * +* Steven Rostedt, Kihon Technologies Inc. +* Added light softlockup detection off of what Daniel Walker of +* MontaVista started. +* * this code detects soft lockups: incidents in where on a CPU * the kernel does not reschedule for 10 seconds or more. */
@@ -20,9 +24,7 @@ static DEFINE_PER_CPU(unsigned long, timeout) = INITIAL_JIFFIES; static DEFINE_PER_CPU(unsigned long, timestamp) = INITIAL_JIFFIES; static DEFINE_PER_CPU(unsigned long, print_timestamp) = INITIAL_JIFFIES; -static DEFINE_PER_CPU(struct task_struct *, prev_task); static DEFINE_PER_CPU(struct task_struct *, watchdog_task); -static DEFINE_PER_CPU(unsigned long, task_counter);static int did_panic =0 ; static int softlock_panic(struct notifier_block *this, unsigned long event,
@@ -42,6 +44,11 @@per_cpu (timestamp,raw_smp_processor_id ()) = jiffies; } +void touch_light_softlockup_watchdog (void ) +{ + current->softlockup_count =0 ; +} +/* * This callback runs from the timer interrupt, and checks * whether the watchdog thread has hung or not:
@@ -59,24 +66,20 @@if (!per_cpu (watchdog_task, this_cpu))return ; -if (per_cpu (prev_task, this_cpu) != current || - !rt_task (current)) { -per_cpu (prev_task, this_cpu) = current; -per_cpu (task_counter, this_cpu) =0 ; - } -else if ((++per_cpu (task_counter, this_cpu) >10 ) &&printk_ratelimit ()) { - -spin_lock (&print_lock); -printk (KERN_ERR "BUG: possible soft lockup detected on CPU#%u! %lu-%lu(%lu)\n" , - this_cpu, jiffies, timestamp, timeout); -printk ("curr=%s:%d\n" ,current->comm,current->pid); - -dump_stack (); +if (current->pid) { +if (++current->softlockup_count >10 ) { +spin_lock (&print_lock); +printk (KERN_ERR "BUG: possible soft lockup detected on CPU#%u! %lu-%lu(%lu)\n" , + this_cpu, jiffies, timestamp, timeout); +printk ("curr=%s:%d count=%ld\n" ,current->comm,current->pid, + current->softlockup_count); +dump_stack ();#if defined(__i386__) && defined(CONFIG_SMP ) -nmi_show_all_regs (); +nmi_show_all_regs ();#endif -spin_unlock (&print_lock); -per_cpu (task_counter, this_cpu) =0 ; +spin_unlock (&print_lock); +touch_light_softlockup_watchdog (); + } }wake_up_process (per_cpu (watchdog_task, this_cpu));
@@ -101,7 +104,6 @@nmi_show_all_regs ();#endif spin_unlock (&print_lock); -per_cpu (task_counter, this_cpu) =0 ; } }
include/linux/sched.h +10 -0
@@ -307,6 +307,7 @@extern void softlockup_tick (void );extern void spawn_softlockup_task (void );extern void touch_softlockup_watchdog (void ); +extern void touch_light_softlockup_watchdog (void );#else static inline void softlockup_tick (void ) {
@@ -317,6 +318,9 @@static inline void touch_softlockup_watchdog (void ) { } +static inline void touch_light_softlockup_watchdog (void ) +{ +}#endif /* Attach to any functions which should be ignored in wchan output. */
@@ -898,6 +902,12 @@#ifdef CONFIG_DEBUG_PREEMPT int lock_count;#endif +#ifdef CONFIG_DETECT_SOFTLOCKUP +unsigned long softlockup_count;/* Count to keep track how long the +* thread is in the kernel without +* sleeping. +*/ +#endif /* realtime bits */ struct list_head delayed_put;struct plist pi_waiters;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Quoted 5 lines · Steven Rostedt
Ingo,
This was my final version of the softlockup patch. Do you have any comments on it? I wasn't sure if you were waiting for any more debate on this patch or not.
ok, looks good - i've applied it and released the -52-14 PREEMPT_RT patch.
Ingo
Quoted 3 lines · Ingo Molnar
ok, looks good - i've applied it and released the -52-14
PREEMPT_RTpatch.
Does not compile if RCU stats are enabled but torture test disabled.
Lee
fs/proc/proc_misc.c renamed from fs/proc/proc_misc.c.orig +4 -0
@@ -654,6 +654,7 @@return proc_calc_metrics (page, start, off, count, eof, len); } +#ifdef CONFIG_RCU_TORTURE_TEST int rcu_read_proc_torture_writer (char *page,char **start,off_t off,int count,int *eof,void *data) {
@@ -683,6 +684,7 @@ len =rcu_read_proc_torture_stats_data (page);return proc_calc_metrics (page, start, off, count, eof, len); } +#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ #endif /* #ifdef CONFIG_RCU_STATS */ void __init proc_misc_init (void )
@@ -712,9 +714,11 @@ {"rcugp", rcu_read_proc_gp}, {"rcuptrs", rcu_read_proc_ptrs}, {"rcuctrs", rcu_read_proc_ctrs}, +#ifdef CONFIG_RCU_TORTURE_TEST {"rcutw", rcu_read_proc_torture_writer}, {"rcutr", rcu_read_proc_torture_reader}, {"rcuts", rcu_read_proc_torture_stats}, +#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ #endif /* #ifdef CONFIG_RCU_STATS */ {NULL,} };
Lee
Quoted 6 lines · Lee Revell
Quoted 3 lines · Ingo Molnar
ok, looks good - i've applied it and released the -52-14
PREEMPT_RTpatch.Does not compile if RCU stats are enabled but torture test disabled.
My bad. Updated RCU-only portion of the patch included below, applies to 2.6.13-rc4. Fixes the following problems:
o Cannot compile RCU stats without torture test.
o Cannot compile torture test without RCU stats.
o Cannot compile torture test against "classic RCU".
o A few "#ifdef CONFIG_PREEMPT_RCU" segments within an enclosing
"#ifndef CONFIG_PREEMPT_RCU" (harmless, just removed them).
o Lack of documentation for the RCU /proc entries.
The resulting patch compiles in the following configurations, and has been tested on x86 and ppc64:
o CONFIG_RCU_TORTURE_TEST:
o CONFIG_RCU_STATS & CONFIG_PREEMPT & CONFIG_PREEMPT_RCU
o !CONFIG_RCU_STATS & CONFIG_PREEMPT & CONFIG_PREEMPT_RCU
o !CONFIG_RCU_STATS & CONFIG_PREEMPT & !CONFIG_PREEMPT_RCU
o !CONFIG_RCU_STATS & !CONFIG_PREEMPT & !CONFIG_PREEMPT_RCU
And ditto with !CONFIG_RCU_TORTURE_TEST. Note that one cannot do CONFIG_RCU_STATS with !CONFIG_PREEMPT_RCU, since CONFIG_RCU_STATS is currently only capable of working with CONFIG_PREEMPT_RCU's internal data structures. One for the todo list. In principle, one could do CONFIG_PREEMPT_RCU & !CONFIG_PREEMPT, but there is little point in having preemptible RCU read-side critical sections in a non-preemptible kernel. I will make this work later (but only for performance comparison purposes) when I have the heavyweight instructions cleaned out of rcu_read_lock() and rcu_read_unlock().
And yes, "classic RCU" does pass the torture test. Though I got a bit of a scare with a broken version of CONFIG_RCU_TORTURE_TEST. ;-)
Thanx, Paul
---
Documentation/RCU/proc.txt | 207 +++++++++++ fs/proc/proc_misc.c | 85 ++++ include/linux/rcupdate.h | 29 + include/linux/sched.h | 5 kernel/Kconfig.preempt | 35 ++ kernel/rcupdate.c | 780 +++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 1106 insertions(+), 35 deletions(-)
Documentation/RCU/proc.txt +207 -0
@@ -0,0 +1,207 @@ +/proc Filesystem Entries for RCU + + +CONFIG_RCU_STATS + +The CONFIG_RCU_STATS config option is available only in conjunction with +CONFIG_PREEMPT_RCU. It makes four /proc entries available, namely: rcuctrs, +rcuptrs, rcugp, and rcustats. + +/proc/rcuctrs + + CPU last cur + 0 1 1 + 1 1 1 + 2 1 1 + 3 0 2 + ggp = 230725 + +This displays the number of processes that started RCU read-side critical +sections on each CPU. In absence of preemption, the "last" and "cur" +counts for a given CPU will always sum to one. Therefore, in the example +output above, each CPU has started one RCU read-side critical section +that was later preempted. The "last" column counts RCU read-side critical +sections that started prior to the last counter flip, while the "cur" +column counts critical sections that started after the last counter flip. + +The "ggp" count is a count of the number of counter flips since boot. +Since this is shown as an odd number, the "cur" counts are stored in +the zero-th element of each of the per-CPU arrays, and the "last" counts +are stored in the first element of each of the per-CPU arrays. + + +/proc/rcuptrs + + nl=c04c7160/c04c7960 nt=c04c72d0 + wl=c04c7168/c04c794c wt=c04c72bc dl=c04c7170/00000000 dt=c04c7170 + +This displays the head and tail of each of CONFIG_PREEMPT_RCU's three +callback lists. This will soon change to display this on a per-CPU +basis, since each CPU will soon have its own set of callback lists. +In the example above, the "next" list header is located at hex address +0xc04c7160, the first element on the list at hex address 0xc04c7960, +and the last element on the list at hex address 0xc04c72d0. The "wl=" +and "wt=" output is similar for the "wait" list, and the "dl=" and "dt=" +output for the "done" list. The "done" list is normally emptied very +quickly after being filled, so will usually be empty as shown above. +Note that the tail pointer points into the list header in this case. + +Callbacks are placed in the "next" list by call_rcu(), moved to the +"wait" list after the next counter flip, and moved to the "done" list +on the counter flip after that. Once on the "done" list, the callbacks +are invoked. + + +/proc/rcugp + + oldggp=241419 newggp=241421 + +This entry invokes synchronize_rcu() and prints out the number of counter +flips since boot before and after the synchronize_rcu(). These two +numbers will always differ by at least two. Unless RCU is broken. ;-) + + +/proc/rcustats + + ggp=242416 lgp=242416 sr=0 rcc=396233 + na=2090938 nl=9 wa=2090929 wl=9 dl=0 dr=2090920 di=2090920 + rtf1=22230730 rtf2=20139162 rtf3=242416 rtfe1=2085911 rtfe2=5657 rtfe3=19896746 + +The quantities printed are as follows: + +o "ggp=": The number of flips since boot. + +o "lgp=": The number of flips sensed by the local structure since + boot. This will soon be per-CPU. + +o "sr=": The number of explicit call to synchronize_rcu(). + Except that this is currently broken, so always reads as zero. + It is likely to be removed... + +o "rcc=": The number of calls to rcu_check_callbacks(). + +o "na=": The number of callbacks that call_rcu() has registered + since boot. + +o "nl=": The number of callbacks currently on the "next" list. + +o "wa=": The number of callbacks that have moved to the "wait" + list since boot. + +o "wl=": The number of callbacks currently on the "wait" list. + +o "da=": The number of callbacks that have been moved to the + "done" list since boot. + +o "dl=": The number of callbacks currently on the "done" list. + +o "dr=": The number of callbacks that have been removed from the + "done" list since boot. + +o "di=": The number of callbacks that have been invoked after being + removed from the "done" list. + +o "rtf1=": The number of attempts to flip the counters. + +o "rtf2=": The number of attempts to flip the counters that successfully + acquired the fliplock. + +o "rtf3=": The number of successful counter flips. + +o "rtfe1=": The number of attempts to flip the counters that failed + due to the lock being held by someone else. + +o "rtfe2=": The number of attempts to flip the counters that were + abandoned due to someone else doing the job for us. + +o "rtfe3=": The number of attempts to flip the counters that failed + due to some task still being in an RCU read-side critical section + starting from before the last successful counter flip. + + +CONFIG_RCU_TORTURE_TEST + +The CONFIG_RCU_TORTURE_TEST config option is available for all RCU +implementations. It makes three /proc entries available, namely: rcutw, +rcutr, and rcuts. + + +/proc/rcutw + +Reading this entry starts a new torture test, or ends an earlier one +if one is already in progress (in other words, there can be only one +writer at a time). This sleeps uninterruptibly, so be sure to run +it in the background. One could argue that it would be good to have +multiple writers, but Linux uses RCU heavily enough that you will get +write-side contention whether you want it or not. If you want additional +write-side contention, repeatedly create and destroy several large file +trees in parallel. Or use some other RCU-protected update. + + +/proc/rcutr + +Reading this entry starts a new torture reader, which runs until sent +a signal (e.g., control-C). If testing an RCU implementation with +preemptible read-side critical sections, make sure to spawn at least +two /proc/rcutr instances for each CPU. + + +/proc/rcuts + +Displays the current state of the torture test: + + ggp = 20961 + rtc: c04496f4 ver: 8734 tfle: 0 rta: 8734 rtaf: 0 rtf: 8715 + Reader Pipe: 88024120 63914 0 0 0 0 0 0 0 0 0 + Reader Batch: 88024097 63937 0 0 0 0 0 0 0 0 + Free-Block Circulation: 8733 8731 8729 8727 8725 8723 8721 8719 8717 8715 0 + +The entries are as follows: + +o "ggp": The number of counter flips (or batches) since boot. + +o "rtc": The hexadecimal address of the structure currently visible + to readers. + +o "ver": The number of times since boot that the rcutw writer task + has changed the structure visible to readers. + +o "tfle": If non-zero, indicates that the "torture freelist" + containing structure to be placed into the "rtc" area is empty. + This condition is important, since it can fool you into thinking + that RCU is working when it is not. :-/ + +o "rta": Number of structures allocated from the torture freelist. + +o "rtaf": Number of allocations from the torture freelist that have + failed due to the list being empty. + +o "rtf": Number of frees into the torture freelist. + +o "Reader Pipe": Histogram of "ages" of structures seen by readers. + If any entries past the first two are non-zero, RCU is broken. + And /proc/rcuts prints "!!!" to make sure you notice. The age + of a newly allocated structure is zero, it becomes one when + removed from reader visibility, and is incremented once per + grace period subsequently -- and is freed after passing through + (RCU_TORTURE_PIPE_LEN-2) grace periods. + + The output displayed above was taken from a correctly working + RCU. If you want to see what it looks like when broken, break + it yourself. ;-) + +o "Reader Batch": Another histogram of "ages" of structures seen + by readers, but in terms of counter flips (or batches) rather + than in terms of grace periods. The legal number of non-zero + entries is again two. The reason for this separate view is + that it is easier to get the third entry to show up in the + "Reader Batch" list than in the "Reader Pipe" list. + +o "Free-Block Circulation": Shows the number of torture structures + that have reached a given point in the pipeline. The first element + should closely correspond to the number of structures allocated, + the second to the number that have been removed from reader view, + and all but the last remaining to the corresponding number of + passes through a grace period. The last entry should be zero, + as it is only incremented if a torture structure's counter + somehow gets incremented farther than it should.
fs/proc/proc_misc.c +85 -0
97 lines not on this page · raw message
include/linux/rcupdate.h +27 -2
@@ -59,6 +59,7 @@ struct rcu_head { } while (0) +#ifndef CONFIG_PREEMPT_RCU /* Global control variables for rcupdate callback mechanism. */ struct rcu_ctrlblk {
@@ -183,14 +184,26 @@ static inline int rcu_pending(int cpu)* * It is illegal to block while in an RCU read-side critical section. */ -#define rcu_read_lock () preempt_disable() +#define rcu_read_lock preempt_disable/** * rcu_read_unlock - marks the end of an RCU read-side critical section. * * See rcu_read_lock() for more information. */ -#define rcu_read_unlock () preempt_enable() +#define rcu_read_unlock preempt_enable + +#else /* #ifndef CONFIG_PREEMPT_RCU */ + +#define rcu_qsctr_inc (cpu) +#define rcu_bh_qsctr_inc (cpu) +#define call_rcu_bh (head, rcu) call_rcu(head, rcu) + +extern void rcu_read_lock (void ); +extern void rcu_read_unlock (void ); +extern int rcu_pending (int cpu); + +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ /* * So where is rcu_write_lock()? It does not exist, as there is no
@@ -213,14 +226,22 @@ static inline int rcu_pending(int cpu)* can use just rcu_read_lock(). * */ +#ifndef CONFIG_PREEMPT_RCU #define rcu_read_lock_bh () local_bh_disable() +#else /* #ifndef CONFIG_PREEMPT_RCU */ +#define rcu_read_lock_bh () { rcu_read_lock(); local_bh_disable(); } +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ /* * rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section * * See rcu_read_lock_bh() for more information. */ +#ifndef CONFIG_PREEMPT_RCU #define rcu_read_unlock_bh () local_bh_enable() +#else /* #ifndef CONFIG_PREEMPT_RCU */ +#define rcu_read_unlock_bh () { local_bh_enable(); rcu_read_unlock(); } +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ /** * rcu_dereference - fetch an RCU-protected pointer in an
@@ -269,7 +290,11 @@ static inline int rcu_pending(int cpu)* synchronize_kernel() API. In contrast, synchronize_rcu() only * guarantees that rcu_read_lock() sections will have completed. */ +#ifndef CONFIG_PREEMPT_RCU #define synchronize_sched () synchronize_rcu() +#else /* #ifndef CONFIG_PREEMPT_RCU */ +extern void synchronize_sched (void ); +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ extern void rcu_init (void );extern void rcu_check_callbacks (int cpu,int user);
include/linux/sched.h +5 -0
@@ -623,6 +623,11 @@ struct task_struct {cpumask_t cpus_allowed;unsigned int time_slice, first_time_slice; +#ifdef CONFIG_PREEMPT_RCU +int rcu_read_lock_nesting; +atomic_t *rcu_flipctr1; +atomic_t *rcu_flipctr2; +#endif #ifdef CONFIG_SCHEDSTATS struct sched_info sched_info;#endif
kernel/Kconfig.preempt +35 -0
@@ -63,3 +63,38 @@ config PREEMPT_BKL Say Y here if you are building a kernel for a desktop system. Say N if you are unsure. +config PREEMPT_RCU + bool "Preemptible RCU" + default n + depends on PREEMPT + help + This option reduces the latency of the kernel by making certain + RCU sections preemptible. Normally RCU code is non-preemptible, if + this option is selected then read-only RCU sections become + preemptible. This helps latency, but may expose bugs due to + now-naive assumptions about each RCU read-side critical section + remaining on a given CPU through its execution. + + Say N if you are unsure. + +config RCU_STATS + bool "/proc stats for preemptible RCU read-side critical sections" + depends on PREEMPT_RCU + default y + help + This option provides /proc stats to provide debugging info for + the preemptible realtime RCU implementation. + + Say Y here if you want to see RCU stats in /proc + Say N if you are unsure. + +config RCU_TORTURE_TEST + bool "/proc torture tests for RCU" + default y + help + This option provides /proc files that run torture tests on + the preemptible realtime RCU implementation. + + Say Y here if you want to be able to run RCU torture tests. + Say N if you are unsure. +
kernel/rcupdate.c +747 -33
824 lines not on this page · raw message
PATCH 1/1 Real-Time Preemption, -RT-2.6.13-rc4-V0.7.52-16
Quoted 2 lines · Paul E. McKenney
Updated RCU-only portion of the patch included below, applies to
2.6.13-rc4. [...]
thanks - i've put it into the -RT tree and have released the -52-16 patch, which can be downloaded from the usual place:
http://redhat.com/~mingo/realtime-preempt/
to build a -V0.7.52-16 tree, the following patches should to be applied:
http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.12.tar.bz2
http://kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.13-rc4.bz2
http://redhat.com/~mingo/realtime-preempt/realtime-preempt-2.6.13-rc4-RT-V0.7.52-16
Ingo