aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2012-11-14 19:26:40 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-01-08 17:14:55 -0500
commit52494535103986dbbf689b44d8c2c7efe2132b16 (patch)
tree88dd5a9d064608e9711c36f05b3b4aab8e255a4f
parentdc975e94f322e60fa8fcc44dec1820fde4de174c (diff)
rcu: Reduce rcutorture tracing
Currently, rcutorture traces every read-side access. This can be problematic because even a two-minute rcutorture run on a two-CPU system can generate 28,853,363 reads. Normally, only a failing read is of interest, so this commit traces adjusts rcutorture's tracing to only trace failing reads. The resulting event tracing records the time and the ->completed value captured at the beginning of the RCU read-side critical section, allowing correlation with other event-tracing messages. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org> [ paulmck: Add fix to build problem located by Randy Dunlap based on diagnosis by Steven Rostedt. ]
-rw-r--r--include/linux/rcupdate.h13
-rw-r--r--include/trace/events/rcu.h19
-rw-r--r--kernel/rcupdate.c9
-rw-r--r--kernel/rcutorture.c31
-rw-r--r--lib/Kconfig.debug1
5 files changed, 55 insertions, 18 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 275aa3f1062d..7f89cea596e1 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -53,7 +53,10 @@ extern int rcutorture_runnable; /* for sysctl */
53extern void rcutorture_record_test_transition(void); 53extern void rcutorture_record_test_transition(void);
54extern void rcutorture_record_progress(unsigned long vernum); 54extern void rcutorture_record_progress(unsigned long vernum);
55extern void do_trace_rcu_torture_read(char *rcutorturename, 55extern void do_trace_rcu_torture_read(char *rcutorturename,
56 struct rcu_head *rhp); 56 struct rcu_head *rhp,
57 unsigned long secs,
58 unsigned long c_old,
59 unsigned long c);
57#else 60#else
58static inline void rcutorture_record_test_transition(void) 61static inline void rcutorture_record_test_transition(void)
59{ 62{
@@ -63,9 +66,13 @@ static inline void rcutorture_record_progress(unsigned long vernum)
63} 66}
64#ifdef CONFIG_RCU_TRACE 67#ifdef CONFIG_RCU_TRACE
65extern void do_trace_rcu_torture_read(char *rcutorturename, 68extern void do_trace_rcu_torture_read(char *rcutorturename,
66 struct rcu_head *rhp); 69 struct rcu_head *rhp,
70 unsigned long secs,
71 unsigned long c_old,
72 unsigned long c);
67#else 73#else
68#define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) 74#define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
75 do { } while (0)
69#endif 76#endif
70#endif 77#endif
71 78
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index d4f559b1ec34..09af021c8e96 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -523,22 +523,30 @@ TRACE_EVENT(rcu_batch_end,
523 */ 523 */
524TRACE_EVENT(rcu_torture_read, 524TRACE_EVENT(rcu_torture_read,
525 525
526 TP_PROTO(char *rcutorturename, struct rcu_head *rhp), 526 TP_PROTO(char *rcutorturename, struct rcu_head *rhp,
527 unsigned long secs, unsigned long c_old, unsigned long c),
527 528
528 TP_ARGS(rcutorturename, rhp), 529 TP_ARGS(rcutorturename, rhp, secs, c_old, c),
529 530
530 TP_STRUCT__entry( 531 TP_STRUCT__entry(
531 __field(char *, rcutorturename) 532 __field(char *, rcutorturename)
532 __field(struct rcu_head *, rhp) 533 __field(struct rcu_head *, rhp)
534 __field(unsigned long, secs)
535 __field(unsigned long, c_old)
536 __field(unsigned long, c)
533 ), 537 ),
534 538
535 TP_fast_assign( 539 TP_fast_assign(
536 __entry->rcutorturename = rcutorturename; 540 __entry->rcutorturename = rcutorturename;
537 __entry->rhp = rhp; 541 __entry->rhp = rhp;
542 __entry->secs = secs;
543 __entry->c_old = c_old;
544 __entry->c = c;
538 ), 545 ),
539 546
540 TP_printk("%s torture read %p", 547 TP_printk("%s torture read %p %luus c: %lu %lu",
541 __entry->rcutorturename, __entry->rhp) 548 __entry->rcutorturename, __entry->rhp,
549 __entry->secs, __entry->c_old, __entry->c)
542); 550);
543 551
544/* 552/*
@@ -608,7 +616,8 @@ TRACE_EVENT(rcu_barrier,
608#define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0) 616#define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0)
609#define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \ 617#define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \
610 do { } while (0) 618 do { } while (0)
611#define trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) 619#define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
620 do { } while (0)
612#define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0) 621#define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0)
613 622
614#endif /* #else #ifdef CONFIG_RCU_TRACE */ 623#endif /* #else #ifdef CONFIG_RCU_TRACE */
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index a2cf76177b44..303359d1ca88 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -404,11 +404,14 @@ EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
404#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ 404#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
405 405
406#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE) 406#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE)
407void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp) 407void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp,
408 unsigned long secs,
409 unsigned long c_old, unsigned long c)
408{ 410{
409 trace_rcu_torture_read(rcutorturename, rhp); 411 trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c);
410} 412}
411EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read); 413EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read);
412#else 414#else
413#define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) 415#define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
416 do { } while (0)
414#endif 417#endif
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 31dea01c85fd..a583f1ce713d 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -46,6 +46,7 @@
46#include <linux/stat.h> 46#include <linux/stat.h>
47#include <linux/srcu.h> 47#include <linux/srcu.h>
48#include <linux/slab.h> 48#include <linux/slab.h>
49#include <linux/trace_clock.h>
49#include <asm/byteorder.h> 50#include <asm/byteorder.h>
50 51
51MODULE_LICENSE("GPL"); 52MODULE_LICENSE("GPL");
@@ -1028,7 +1029,6 @@ void rcutorture_trace_dump(void)
1028 return; 1029 return;
1029 if (atomic_xchg(&beenhere, 1) != 0) 1030 if (atomic_xchg(&beenhere, 1) != 0)
1030 return; 1031 return;
1031 do_trace_rcu_torture_read(cur_ops->name, (struct rcu_head *)~0UL);
1032 ftrace_dump(DUMP_ALL); 1032 ftrace_dump(DUMP_ALL);
1033} 1033}
1034 1034
@@ -1042,13 +1042,16 @@ static void rcu_torture_timer(unsigned long unused)
1042{ 1042{
1043 int idx; 1043 int idx;
1044 int completed; 1044 int completed;
1045 int completed_end;
1045 static DEFINE_RCU_RANDOM(rand); 1046 static DEFINE_RCU_RANDOM(rand);
1046 static DEFINE_SPINLOCK(rand_lock); 1047 static DEFINE_SPINLOCK(rand_lock);
1047 struct rcu_torture *p; 1048 struct rcu_torture *p;
1048 int pipe_count; 1049 int pipe_count;
1050 unsigned long long ts;
1049 1051
1050 idx = cur_ops->readlock(); 1052 idx = cur_ops->readlock();
1051 completed = cur_ops->completed(); 1053 completed = cur_ops->completed();
1054 ts = trace_clock_local();
1052 p = rcu_dereference_check(rcu_torture_current, 1055 p = rcu_dereference_check(rcu_torture_current,
1053 rcu_read_lock_bh_held() || 1056 rcu_read_lock_bh_held() ||
1054 rcu_read_lock_sched_held() || 1057 rcu_read_lock_sched_held() ||
@@ -1058,7 +1061,6 @@ static void rcu_torture_timer(unsigned long unused)
1058 cur_ops->readunlock(idx); 1061 cur_ops->readunlock(idx);
1059 return; 1062 return;
1060 } 1063 }
1061 do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
1062 if (p->rtort_mbtest == 0) 1064 if (p->rtort_mbtest == 0)
1063 atomic_inc(&n_rcu_torture_mberror); 1065 atomic_inc(&n_rcu_torture_mberror);
1064 spin_lock(&rand_lock); 1066 spin_lock(&rand_lock);
@@ -1071,10 +1073,16 @@ static void rcu_torture_timer(unsigned long unused)
1071 /* Should not happen, but... */ 1073 /* Should not happen, but... */
1072 pipe_count = RCU_TORTURE_PIPE_LEN; 1074 pipe_count = RCU_TORTURE_PIPE_LEN;
1073 } 1075 }
1074 if (pipe_count > 1) 1076 completed_end = cur_ops->completed();
1077 if (pipe_count > 1) {
1078 unsigned long __maybe_unused ts_rem = do_div(ts, NSEC_PER_USEC);
1079
1080 do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts,
1081 completed, completed_end);
1075 rcutorture_trace_dump(); 1082 rcutorture_trace_dump();
1083 }
1076 __this_cpu_inc(rcu_torture_count[pipe_count]); 1084 __this_cpu_inc(rcu_torture_count[pipe_count]);
1077 completed = cur_ops->completed() - completed; 1085 completed = completed_end - completed;
1078 if (completed > RCU_TORTURE_PIPE_LEN) { 1086 if (completed > RCU_TORTURE_PIPE_LEN) {
1079 /* Should not happen, but... */ 1087 /* Should not happen, but... */
1080 completed = RCU_TORTURE_PIPE_LEN; 1088 completed = RCU_TORTURE_PIPE_LEN;
@@ -1094,11 +1102,13 @@ static int
1094rcu_torture_reader(void *arg) 1102rcu_torture_reader(void *arg)
1095{ 1103{
1096 int completed; 1104 int completed;
1105 int completed_end;
1097 int idx; 1106 int idx;
1098 DEFINE_RCU_RANDOM(rand); 1107 DEFINE_RCU_RANDOM(rand);
1099 struct rcu_torture *p; 1108 struct rcu_torture *p;
1100 int pipe_count; 1109 int pipe_count;
1101 struct timer_list t; 1110 struct timer_list t;
1111 unsigned long long ts;
1102 1112
1103 VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); 1113 VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
1104 set_user_nice(current, 19); 1114 set_user_nice(current, 19);
@@ -1112,6 +1122,7 @@ rcu_torture_reader(void *arg)
1112 } 1122 }
1113 idx = cur_ops->readlock(); 1123 idx = cur_ops->readlock();
1114 completed = cur_ops->completed(); 1124 completed = cur_ops->completed();
1125 ts = trace_clock_local();
1115 p = rcu_dereference_check(rcu_torture_current, 1126 p = rcu_dereference_check(rcu_torture_current,
1116 rcu_read_lock_bh_held() || 1127 rcu_read_lock_bh_held() ||
1117 rcu_read_lock_sched_held() || 1128 rcu_read_lock_sched_held() ||
@@ -1122,7 +1133,6 @@ rcu_torture_reader(void *arg)
1122 schedule_timeout_interruptible(HZ); 1133 schedule_timeout_interruptible(HZ);
1123 continue; 1134 continue;
1124 } 1135 }
1125 do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
1126 if (p->rtort_mbtest == 0) 1136 if (p->rtort_mbtest == 0)
1127 atomic_inc(&n_rcu_torture_mberror); 1137 atomic_inc(&n_rcu_torture_mberror);
1128 cur_ops->read_delay(&rand); 1138 cur_ops->read_delay(&rand);
@@ -1132,10 +1142,17 @@ rcu_torture_reader(void *arg)
1132 /* Should not happen, but... */ 1142 /* Should not happen, but... */
1133 pipe_count = RCU_TORTURE_PIPE_LEN; 1143 pipe_count = RCU_TORTURE_PIPE_LEN;
1134 } 1144 }
1135 if (pipe_count > 1) 1145 completed_end = cur_ops->completed();
1146 if (pipe_count > 1) {
1147 unsigned long __maybe_unused ts_rem =
1148 do_div(ts, NSEC_PER_USEC);
1149
1150 do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu,
1151 ts, completed, completed_end);
1136 rcutorture_trace_dump(); 1152 rcutorture_trace_dump();
1153 }
1137 __this_cpu_inc(rcu_torture_count[pipe_count]); 1154 __this_cpu_inc(rcu_torture_count[pipe_count]);
1138 completed = cur_ops->completed() - completed; 1155 completed = completed_end - completed;
1139 if (completed > RCU_TORTURE_PIPE_LEN) { 1156 if (completed > RCU_TORTURE_PIPE_LEN) {
1140 /* Should not happen, but... */ 1157 /* Should not happen, but... */
1141 completed = RCU_TORTURE_PIPE_LEN; 1158 completed = RCU_TORTURE_PIPE_LEN;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 3a353091a903..7d83f52fbade 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1008,6 +1008,7 @@ config RCU_CPU_STALL_INFO
1008config RCU_TRACE 1008config RCU_TRACE
1009 bool "Enable tracing for RCU" 1009 bool "Enable tracing for RCU"
1010 depends on DEBUG_KERNEL 1010 depends on DEBUG_KERNEL
1011 select TRACE_CLOCK
1011 help 1012 help
1012 This option provides tracing in RCU which presents stats 1013 This option provides tracing in RCU which presents stats
1013 in debugfs for debugging RCU implementation. 1014 in debugfs for debugging RCU implementation.