diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2012-11-14 19:26:40 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-01-08 17:14:55 -0500 |
commit | 52494535103986dbbf689b44d8c2c7efe2132b16 (patch) | |
tree | 88dd5a9d064608e9711c36f05b3b4aab8e255a4f /kernel | |
parent | dc975e94f322e60fa8fcc44dec1820fde4de174c (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. ]
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/rcupdate.c | 9 | ||||
-rw-r--r-- | kernel/rcutorture.c | 31 |
2 files changed, 30 insertions, 10 deletions
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) |
407 | void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp) | 407 | void 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 | } |
411 | EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read); | 413 | EXPORT_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 | ||
51 | MODULE_LICENSE("GPL"); | 52 | MODULE_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 | |||
1094 | rcu_torture_reader(void *arg) | 1102 | rcu_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; |