diff options
-rw-r--r-- | include/linux/rcutree.h | 9 | ||||
-rw-r--r-- | kernel/rcutree.c | 25 | ||||
-rw-r--r-- | kernel/rcutree_trace.c | 64 |
3 files changed, 90 insertions, 8 deletions
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 58b2aa5312b9..5a5153806c42 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h | |||
@@ -161,8 +161,15 @@ struct rcu_data { | |||
161 | unsigned long offline_fqs; /* Kicked due to being offline. */ | 161 | unsigned long offline_fqs; /* Kicked due to being offline. */ |
162 | unsigned long resched_ipi; /* Sent a resched IPI. */ | 162 | unsigned long resched_ipi; /* Sent a resched IPI. */ |
163 | 163 | ||
164 | /* 5) For future __rcu_pending statistics. */ | 164 | /* 5) __rcu_pending() statistics. */ |
165 | long n_rcu_pending; /* rcu_pending() calls since boot. */ | 165 | long n_rcu_pending; /* rcu_pending() calls since boot. */ |
166 | long n_rp_qs_pending; | ||
167 | long n_rp_cb_ready; | ||
168 | long n_rp_cpu_needs_gp; | ||
169 | long n_rp_gp_completed; | ||
170 | long n_rp_gp_started; | ||
171 | long n_rp_need_fqs; | ||
172 | long n_rp_need_nothing; | ||
166 | 173 | ||
167 | int cpu; | 174 | int cpu; |
168 | }; | 175 | }; |
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d2a372fb0b9b..0dccfbba6d26 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -1259,31 +1259,44 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1259 | check_cpu_stall(rsp, rdp); | 1259 | check_cpu_stall(rsp, rdp); |
1260 | 1260 | ||
1261 | /* Is the RCU core waiting for a quiescent state from this CPU? */ | 1261 | /* Is the RCU core waiting for a quiescent state from this CPU? */ |
1262 | if (rdp->qs_pending) | 1262 | if (rdp->qs_pending) { |
1263 | rdp->n_rp_qs_pending++; | ||
1263 | return 1; | 1264 | return 1; |
1265 | } | ||
1264 | 1266 | ||
1265 | /* Does this CPU have callbacks ready to invoke? */ | 1267 | /* Does this CPU have callbacks ready to invoke? */ |
1266 | if (cpu_has_callbacks_ready_to_invoke(rdp)) | 1268 | if (cpu_has_callbacks_ready_to_invoke(rdp)) { |
1269 | rdp->n_rp_cb_ready++; | ||
1267 | return 1; | 1270 | return 1; |
1271 | } | ||
1268 | 1272 | ||
1269 | /* Has RCU gone idle with this CPU needing another grace period? */ | 1273 | /* Has RCU gone idle with this CPU needing another grace period? */ |
1270 | if (cpu_needs_another_gp(rsp, rdp)) | 1274 | if (cpu_needs_another_gp(rsp, rdp)) { |
1275 | rdp->n_rp_cpu_needs_gp++; | ||
1271 | return 1; | 1276 | return 1; |
1277 | } | ||
1272 | 1278 | ||
1273 | /* Has another RCU grace period completed? */ | 1279 | /* Has another RCU grace period completed? */ |
1274 | if (ACCESS_ONCE(rsp->completed) != rdp->completed) /* outside of lock */ | 1280 | if (ACCESS_ONCE(rsp->completed) != rdp->completed) { /* outside lock */ |
1281 | rdp->n_rp_gp_completed++; | ||
1275 | return 1; | 1282 | return 1; |
1283 | } | ||
1276 | 1284 | ||
1277 | /* Has a new RCU grace period started? */ | 1285 | /* Has a new RCU grace period started? */ |
1278 | if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) /* outside of lock */ | 1286 | if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) { /* outside lock */ |
1287 | rdp->n_rp_gp_started++; | ||
1279 | return 1; | 1288 | return 1; |
1289 | } | ||
1280 | 1290 | ||
1281 | /* Has an RCU GP gone long enough to send resched IPIs &c? */ | 1291 | /* Has an RCU GP gone long enough to send resched IPIs &c? */ |
1282 | if (ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum) && | 1292 | if (ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum) && |
1283 | ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) | 1293 | ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) { |
1294 | rdp->n_rp_need_fqs++; | ||
1284 | return 1; | 1295 | return 1; |
1296 | } | ||
1285 | 1297 | ||
1286 | /* nothing to do */ | 1298 | /* nothing to do */ |
1299 | rdp->n_rp_need_nothing++; | ||
1287 | return 0; | 1300 | return 0; |
1288 | } | 1301 | } |
1289 | 1302 | ||
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 4b1875ba9404..fe1dcdbf1ca3 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c | |||
@@ -213,7 +213,63 @@ static struct file_operations rcugp_fops = { | |||
213 | .release = single_release, | 213 | .release = single_release, |
214 | }; | 214 | }; |
215 | 215 | ||
216 | static struct dentry *rcudir, *datadir, *datadir_csv, *hierdir, *gpdir; | 216 | static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp) |
217 | { | ||
218 | seq_printf(m, "%3d%cnp=%ld " | ||
219 | "qsp=%ld cbr=%ld cng=%ld gpc=%ld gps=%ld nf=%ld nn=%ld\n", | ||
220 | rdp->cpu, | ||
221 | cpu_is_offline(rdp->cpu) ? '!' : ' ', | ||
222 | rdp->n_rcu_pending, | ||
223 | rdp->n_rp_qs_pending, | ||
224 | rdp->n_rp_cb_ready, | ||
225 | rdp->n_rp_cpu_needs_gp, | ||
226 | rdp->n_rp_gp_completed, | ||
227 | rdp->n_rp_gp_started, | ||
228 | rdp->n_rp_need_fqs, | ||
229 | rdp->n_rp_need_nothing); | ||
230 | } | ||
231 | |||
232 | static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp) | ||
233 | { | ||
234 | int cpu; | ||
235 | struct rcu_data *rdp; | ||
236 | |||
237 | for_each_possible_cpu(cpu) { | ||
238 | rdp = rsp->rda[cpu]; | ||
239 | if (rdp->beenonline) | ||
240 | print_one_rcu_pending(m, rdp); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | static int show_rcu_pending(struct seq_file *m, void *unused) | ||
245 | { | ||
246 | seq_puts(m, "rcu:\n"); | ||
247 | print_rcu_pendings(m, &rcu_state); | ||
248 | seq_puts(m, "rcu_bh:\n"); | ||
249 | print_rcu_pendings(m, &rcu_bh_state); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int rcu_pending_open(struct inode *inode, struct file *file) | ||
254 | { | ||
255 | return single_open(file, show_rcu_pending, NULL); | ||
256 | } | ||
257 | |||
258 | static struct file_operations rcu_pending_fops = { | ||
259 | .owner = THIS_MODULE, | ||
260 | .open = rcu_pending_open, | ||
261 | .read = seq_read, | ||
262 | .llseek = seq_lseek, | ||
263 | .release = single_release, | ||
264 | }; | ||
265 | |||
266 | static struct dentry *rcudir; | ||
267 | static struct dentry *datadir; | ||
268 | static struct dentry *datadir_csv; | ||
269 | static struct dentry *gpdir; | ||
270 | static struct dentry *hierdir; | ||
271 | static struct dentry *rcu_pendingdir; | ||
272 | |||
217 | static int __init rcuclassic_trace_init(void) | 273 | static int __init rcuclassic_trace_init(void) |
218 | { | 274 | { |
219 | rcudir = debugfs_create_dir("rcu", NULL); | 275 | rcudir = debugfs_create_dir("rcu", NULL); |
@@ -238,6 +294,11 @@ static int __init rcuclassic_trace_init(void) | |||
238 | NULL, &rcuhier_fops); | 294 | NULL, &rcuhier_fops); |
239 | if (!hierdir) | 295 | if (!hierdir) |
240 | goto free_out; | 296 | goto free_out; |
297 | |||
298 | rcu_pendingdir = debugfs_create_file("rcu_pending", 0444, rcudir, | ||
299 | NULL, &rcu_pending_fops); | ||
300 | if (!rcu_pendingdir) | ||
301 | goto free_out; | ||
241 | return 0; | 302 | return 0; |
242 | free_out: | 303 | free_out: |
243 | if (datadir) | 304 | if (datadir) |
@@ -257,6 +318,7 @@ static void __exit rcuclassic_trace_cleanup(void) | |||
257 | debugfs_remove(datadir_csv); | 318 | debugfs_remove(datadir_csv); |
258 | debugfs_remove(gpdir); | 319 | debugfs_remove(gpdir); |
259 | debugfs_remove(hierdir); | 320 | debugfs_remove(hierdir); |
321 | debugfs_remove(rcu_pendingdir); | ||
260 | debugfs_remove(rcudir); | 322 | debugfs_remove(rcudir); |
261 | } | 323 | } |
262 | 324 | ||