diff -urN oldtree/include/linux/rcupreempt_trace.h newtree/include/linux/rcupreempt_trace.h --- oldtree/include/linux/rcupreempt_trace.h 1969-12-31 19:00:00.000000000 -0500 +++ newtree/include/linux/rcupreempt_trace.h 2006-10-06 17:58:16.000000000 -0400 @@ -0,0 +1,84 @@ +/* + * Read-Copy Update mechanism for mutual exclusion (RT implementation) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2006 + * + * Author: Paul McKenney + * + * Based on the original work by Paul McKenney + * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. + * Papers: + * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf + * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) + * + * For detailed explanation of Read-Copy Update mechanism see - + * http://lse.sourceforge.net/locking/rcupdate.html + * + */ + +#ifndef __LINUX_RCUPREEMPT_TRACE_H +#define __LINUX_RCUPREEMPT_TRACE_H + +#ifdef __KERNEL__ +#include +#include + +#include + +/* + * PREEMPT_RCU data structures. + */ + +struct rcupreempt_trace { + long next_length; + long next_add; + long wait_length; + long wait_add; + long done_length; + long done_add; + long done_remove; + atomic_t done_invoked; + long rcu_check_callbacks; + atomic_t rcu_try_flip1; + long rcu_try_flip2; + long rcu_try_flip3; + atomic_t rcu_try_flip_e1; + long rcu_try_flip_e2; + long rcu_try_flip_e3; +}; + +#ifdef CONFIG_RCU_TRACE +#define RCU_TRACE(fn, arg) fn(arg); +#else +#define RCU_TRACE(fn, arg) +#endif + +extern void rcupreempt_trace_move2done(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_try_flip1(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_try_flip_e2(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_try_flip_e3(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_try_flip2(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_try_flip3(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_invoke(struct rcupreempt_trace *trace); +extern void rcupreempt_trace_next_add(struct rcupreempt_trace *trace); + +#endif /* __KERNEL__ */ +#endif /* __LINUX_RCUPREEMPT_TRACE_H */ diff -urN oldtree/kernel/Kconfig.preempt newtree/kernel/Kconfig.preempt --- oldtree/kernel/Kconfig.preempt 2006-10-06 17:58:04.000000000 -0400 +++ newtree/kernel/Kconfig.preempt 2006-10-06 17:58:16.000000000 -0400 @@ -89,13 +89,12 @@ endchoice -config RCU_STATS - bool "/proc stats for preemptible RCU read-side critical sections" - depends on PREEMPT_RCU +config RCU_TRACE + bool "Enable tracing for RCU - currently stats in /proc" default y help - This option provides /proc stats to provide debugging info for - the preemptible realtime RCU implementation. + This option provides tracing in RCU which presents /proc + stats for debugging RCU implementation. - Say Y here if you want to see RCU stats in /proc + Say Y here if you want to enable RCU tracing Say N if you are unsure. diff -urN oldtree/kernel/Makefile newtree/kernel/Makefile --- oldtree/kernel/Makefile 2006-10-06 17:58:04.000000000 -0400 +++ newtree/kernel/Makefile 2006-10-06 17:58:16.000000000 -0400 @@ -52,6 +52,7 @@ obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_CLASSIC_RCU) += rcupdate.o rcuclassic.o obj-$(CONFIG_PREEMPT_RCU) += rcupdate.o rcupreempt.o +obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o obj-$(CONFIG_DEBUG_SYNCHRO_TEST) += synchro-test.o obj-$(CONFIG_KEVENT) += kevent/ obj-$(CONFIG_RELAY) += relay.o diff -urN oldtree/kernel/rcupreempt.c newtree/kernel/rcupreempt.c --- oldtree/kernel/rcupreempt.c 2006-10-06 17:58:04.000000000 -0400 +++ newtree/kernel/rcupreempt.c 2006-10-06 17:58:16.000000000 -0400 @@ -48,6 +48,7 @@ #include #include #include +#include /* * PREEMPT_RCU data structures. @@ -63,23 +64,9 @@ struct rcu_head **waittail; struct rcu_head *donelist; struct rcu_head **donetail; -#ifdef CONFIG_RCU_STATS - long n_next_length; - long n_next_add; - long n_wait_length; - long n_wait_add; - long n_done_length; - long n_done_add; - long n_done_remove; - atomic_t n_done_invoked; - long n_rcu_check_callbacks; - atomic_t n_rcu_try_flip1; - long n_rcu_try_flip2; - long n_rcu_try_flip3; - atomic_t n_rcu_try_flip_e1; - long n_rcu_try_flip_e2; - long n_rcu_try_flip_e3; -#endif /* #ifdef CONFIG_RCU_STATS */ +#ifdef CONFIG_RCU_TRACE + struct rcupreempt_trace trace; +#endif /* #ifdef CONFIG_RCU_TRACE */ }; struct rcu_ctrlblk { spinlock_t fliplock; @@ -189,22 +176,14 @@ if (rcu_data.waitlist != NULL) { *rcu_data.donetail = rcu_data.waitlist; rcu_data.donetail = rcu_data.waittail; -#ifdef CONFIG_RCU_STATS - rcu_data.n_done_length += rcu_data.n_wait_length; - rcu_data.n_done_add += rcu_data.n_wait_length; - rcu_data.n_wait_length = 0; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_move2done, &rcu_data.trace); } if (rcu_data.nextlist != NULL) { rcu_data.waitlist = rcu_data.nextlist; rcu_data.waittail = rcu_data.nexttail; rcu_data.nextlist = NULL; rcu_data.nexttail = &rcu_data.nextlist; -#ifdef CONFIG_RCU_STATS - rcu_data.n_wait_length += rcu_data.n_next_length; - rcu_data.n_wait_add += rcu_data.n_next_length; - rcu_data.n_next_length = 0; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_move2wait, &rcu_data.trace); } else { rcu_data.waitlist = NULL; rcu_data.waittail = &rcu_data.waitlist; @@ -229,22 +208,16 @@ unsigned long oldirq; flipctr = rcu_ctrlblk.completed; -#ifdef CONFIG_RCU_STATS - atomic_inc(&rcu_data.n_rcu_try_flip1); -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_try_flip1, &rcu_data.trace); if (unlikely(!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, oldirq))) { -#ifdef CONFIG_RCU_STATS - atomic_inc(&rcu_data.n_rcu_try_flip_e1); -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_try_flip_e1, &rcu_data.trace); return; } if (unlikely(flipctr != rcu_ctrlblk.completed)) { /* Our work is done! ;-) */ -#ifdef CONFIG_RCU_STATS - rcu_data.n_rcu_try_flip_e2++; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_try_flip_e2, &rcu_data.trace); spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, oldirq); return; } @@ -255,14 +228,11 @@ * that started prior to the previous flip. */ -#ifdef CONFIG_RCU_STATS - rcu_data.n_rcu_try_flip2++; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_try_flip2, &rcu_data.trace); for_each_possible_cpu(cpu) { if (atomic_read(&per_cpu(rcu_flipctr, cpu)[!flipctr]) != 0) { -#ifdef CONFIG_RCU_STATS - rcu_data.n_rcu_try_flip_e3++; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_try_flip_e3, + &rcu_data.trace); spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, oldirq); return; } @@ -273,9 +243,7 @@ smp_mb(); rcu_ctrlblk.completed++; -#ifdef CONFIG_RCU_STATS - rcu_data.n_rcu_try_flip3++; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_try_flip3, &rcu_data.trace); spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, oldirq); } @@ -290,9 +258,7 @@ } } spin_lock_irqsave(&rcu_data.lock, oldirq); -#ifdef CONFIG_RCU_STATS - rcu_data.n_rcu_check_callbacks++; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_check_callbacks, &rcu_data.trace); __rcu_advance_callbacks(); if (rcu_data.donelist == NULL) { spin_unlock_irqrestore(&rcu_data.lock, oldirq); @@ -315,18 +281,13 @@ } rcu_data.donelist = NULL; rcu_data.donetail = &rcu_data.donelist; -#ifdef CONFIG_RCU_STATS - rcu_data.n_done_remove += rcu_data.n_done_length; - rcu_data.n_done_length = 0; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_done_remove, &rcu_data.trace); spin_unlock_irqrestore(&rcu_data.lock, flags); while (list) { next = list->next; list->func(list); list = next; -#ifdef CONFIG_RCU_STATS - atomic_inc(&rcu_data.n_done_invoked); -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_invoke, &rcu_data.trace); } } @@ -341,10 +302,7 @@ __rcu_advance_callbacks(); *rcu_data.nexttail = head; rcu_data.nexttail = &head->next; -#ifdef CONFIG_RCU_STATS - rcu_data.n_next_add++; - rcu_data.n_next_length++; -#endif /* #ifdef CONFIG_RCU_STATS */ + RCU_TRACE(rcupreempt_trace_next_add, &rcu_data.trace); spin_unlock_irqrestore(&rcu_data.lock, flags); } @@ -398,9 +356,10 @@ synchronize_rcu(); } -#ifdef CONFIG_RCU_STATS +#ifdef CONFIG_RCU_TRACE int rcu_read_proc_data(char *page) { + struct rcupreempt_trace *trace = &rcu_data.trace; return sprintf(page, "ggp=%ld lgp=%ld rcc=%ld\n" "na=%ld nl=%ld wa=%ld wl=%ld da=%ld dl=%ld dr=%ld di=%d\n" @@ -408,23 +367,23 @@ rcu_ctrlblk.completed, rcu_data.completed, - rcu_data.n_rcu_check_callbacks, + trace->rcu_check_callbacks, - rcu_data.n_next_add, - rcu_data.n_next_length, - rcu_data.n_wait_add, - rcu_data.n_wait_length, - rcu_data.n_done_add, - rcu_data.n_done_length, - rcu_data.n_done_remove, - atomic_read(&rcu_data.n_done_invoked), - - atomic_read(&rcu_data.n_rcu_try_flip1), - rcu_data.n_rcu_try_flip2, - rcu_data.n_rcu_try_flip3, - atomic_read(&rcu_data.n_rcu_try_flip_e1), - rcu_data.n_rcu_try_flip_e2, - rcu_data.n_rcu_try_flip_e3); + trace->next_add, + trace->next_length, + trace->wait_add, + trace->wait_length, + trace->done_add, + trace->done_length, + trace->done_remove, + atomic_read(&trace->done_invoked), + + atomic_read(&trace->rcu_try_flip1), + trace->rcu_try_flip2, + trace->rcu_try_flip3, + atomic_read(&trace->rcu_try_flip_e1), + trace->rcu_try_flip_e2, + trace->rcu_try_flip_e3); } int rcu_read_proc_gp_data(char *page) @@ -463,7 +422,7 @@ return (cnt); } -#endif /* #ifdef CONFIG_RCU_STATS */ +#endif /* #ifdef CONFIG_RCU_TRACE */ EXPORT_SYMBOL_GPL(call_rcu); EXPORT_SYMBOL_GPL(rcu_batches_completed); diff -urN oldtree/kernel/rcupreempt_trace.c newtree/kernel/rcupreempt_trace.c --- oldtree/kernel/rcupreempt_trace.c 1969-12-31 19:00:00.000000000 -0500 +++ newtree/kernel/rcupreempt_trace.c 2006-10-06 17:58:16.000000000 -0400 @@ -0,0 +1,99 @@ +/* + * Read-Copy Update tracing for realtime implementation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2006 + * + * Papers: http://www.rdrop.com/users/paulmck/RCU + * + * For detailed explanation of Read-Copy Update mechanism see - + * Documentation/RCU/ *.txt + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void rcupreempt_trace_move2done(struct rcupreempt_trace *trace) +{ + trace->done_length += trace->wait_length; + trace->done_add += trace->wait_length; + trace->wait_length = 0; +} +void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace) +{ + trace->wait_length += trace->next_length; + trace->wait_add += trace->next_length; + trace->next_length = 0; +} +void rcupreempt_trace_try_flip1(struct rcupreempt_trace *trace) +{ + atomic_inc(&trace->rcu_try_flip1); +} +void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace) +{ + atomic_inc(&trace->rcu_try_flip_e1); +} +void rcupreempt_trace_try_flip_e2(struct rcupreempt_trace *trace) +{ + trace->rcu_try_flip_e2++; +} +void rcupreempt_trace_try_flip_e3(struct rcupreempt_trace *trace) +{ + trace->rcu_try_flip_e3++; +} +void rcupreempt_trace_try_flip2(struct rcupreempt_trace *trace) +{ + trace->rcu_try_flip2++; +} +void rcupreempt_trace_try_flip3(struct rcupreempt_trace *trace) +{ + trace->rcu_try_flip3++; +} +void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace) +{ + trace->rcu_check_callbacks++; +} +void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace) +{ + trace->done_remove += trace->done_length; + trace->done_length = 0; +} +void rcupreempt_trace_invoke(struct rcupreempt_trace *trace) +{ + atomic_inc(&trace->done_invoked); +} +void rcupreempt_trace_next_add(struct rcupreempt_trace *trace) +{ + trace->next_add++; + trace->next_length++; +}