aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2011-04-06 19:01:16 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-05-06 02:16:56 -0400
commit15ba0ba860871cf74b48b1bb47c26c91a66126f3 (patch)
tree2043eeca7d6df62fc0ae918b61abada073f81415
parenta9f4793d8900dc5dc09b3951bdcd4731290e06fe (diff)
rcu: add grace-period age and more kthread state to tracing
This commit adds the age in jiffies of the current grace period along with the duration in jiffies of the longest grace period since boot to the rcu/rcugp debugfs file. It also adds an additional "O" state to kthread tracing to differentiate between the kthread waiting due to having nothing to do on the one hand and waiting due to being on the wrong CPU on the other hand. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r--Documentation/RCU/trace.txt12
-rw-r--r--kernel/rcutree.c10
-rw-r--r--kernel/rcutree.h7
-rw-r--r--kernel/rcutree_trace.c37
4 files changed, 54 insertions, 12 deletions
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
index 40b530dd0fc7..fd4bffb6e8c9 100644
--- a/Documentation/RCU/trace.txt
+++ b/Documentation/RCU/trace.txt
@@ -159,8 +159,8 @@ o "qs" gives an indication of the state of the callback queue
159 the corresponding character is replaced by ".". 159 the corresponding character is replaced by ".".
160 160
161o "kt" is the per-CPU kernel-thread state. The digit preceding 161o "kt" is the per-CPU kernel-thread state. The digit preceding
162 the slash is zero if there is no work pending and 1 otherwise. 162 the first slash is zero if there is no work pending and 1
163 The character after the slash is as follows: 163 otherwise. The character between the slashes is as follows:
164 164
165 "S" The kernel thread is stopped, in other words, all 165 "S" The kernel thread is stopped, in other words, all
166 CPUs corresponding to this rcu_node structure are 166 CPUs corresponding to this rcu_node structure are
@@ -171,10 +171,18 @@ o "kt" is the per-CPU kernel-thread state. The digit preceding
171 "W" The kernel thread is waiting because there is no work 171 "W" The kernel thread is waiting because there is no work
172 for it to do. 172 for it to do.
173 173
174 "O" The kernel thread is waiting because it has been
175 forced off of its designated CPU or because its
176 ->cpus_allowed mask permits it to run on other than
177 its designated CPU.
178
174 "Y" The kernel thread is yielding to avoid hogging CPU. 179 "Y" The kernel thread is yielding to avoid hogging CPU.
175 180
176 "?" Unknown value, indicates a bug. 181 "?" Unknown value, indicates a bug.
177 182
183 The number after the final slash is the CPU that the kthread
184 is actually running on.
185
178o "b" is the batch limit for this CPU. If more than this number 186o "b" is the batch limit for this CPU. If more than this number
179 of RCU callbacks is ready to invoke, then the remainder will 187 of RCU callbacks is ready to invoke, then the remainder will
180 be deferred. 188 be deferred.
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index bb84deca3319..27b6d8de82f6 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -92,6 +92,7 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active);
92 */ 92 */
93static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task); 93static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
94DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); 94DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
95DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu);
95static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq); 96static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq);
96DEFINE_PER_CPU(char, rcu_cpu_has_work); 97DEFINE_PER_CPU(char, rcu_cpu_has_work);
97static char rcu_kthreads_spawnable; 98static char rcu_kthreads_spawnable;
@@ -888,6 +889,8 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
888static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) 889static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
889 __releases(rcu_get_root(rsp)->lock) 890 __releases(rcu_get_root(rsp)->lock)
890{ 891{
892 unsigned long gp_duration;
893
891 WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); 894 WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
892 895
893 /* 896 /*
@@ -895,6 +898,9 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
895 * is seen before the assignment to rsp->completed. 898 * is seen before the assignment to rsp->completed.
896 */ 899 */
897 smp_mb(); /* See above block comment. */ 900 smp_mb(); /* See above block comment. */
901 gp_duration = jiffies - rsp->gp_start;
902 if (gp_duration > rsp->gp_max)
903 rsp->gp_max = gp_duration;
898 rsp->completed = rsp->gpnum; 904 rsp->completed = rsp->gpnum;
899 rsp->signaled = RCU_GP_IDLE; 905 rsp->signaled = RCU_GP_IDLE;
900 rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ 906 rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */
@@ -1583,12 +1589,15 @@ static int rcu_cpu_kthread_should_stop(int cpu)
1583 smp_processor_id() != cpu) { 1589 smp_processor_id() != cpu) {
1584 if (kthread_should_stop()) 1590 if (kthread_should_stop())
1585 return 1; 1591 return 1;
1592 per_cpu(rcu_cpu_kthread_status, cpu) = RCU_KTHREAD_OFFCPU;
1593 per_cpu(rcu_cpu_kthread_cpu, cpu) = raw_smp_processor_id();
1586 local_bh_enable(); 1594 local_bh_enable();
1587 schedule_timeout_uninterruptible(1); 1595 schedule_timeout_uninterruptible(1);
1588 if (!cpumask_equal(&current->cpus_allowed, cpumask_of(cpu))) 1596 if (!cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)))
1589 set_cpus_allowed_ptr(current, cpumask_of(cpu)); 1597 set_cpus_allowed_ptr(current, cpumask_of(cpu));
1590 local_bh_disable(); 1598 local_bh_disable();
1591 } 1599 }
1600 per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
1592 return 0; 1601 return 0;
1593} 1602}
1594 1603
@@ -1656,6 +1665,7 @@ static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu)
1656 if (IS_ERR(t)) 1665 if (IS_ERR(t))
1657 return PTR_ERR(t); 1666 return PTR_ERR(t);
1658 kthread_bind(t, cpu); 1667 kthread_bind(t, cpu);
1668 per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
1659 WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL); 1669 WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL);
1660 per_cpu(rcu_cpu_kthread_task, cpu) = t; 1670 per_cpu(rcu_cpu_kthread_task, cpu) = t;
1661 wake_up_process(t); 1671 wake_up_process(t);
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index 67341dbebd95..37502a27a072 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -93,8 +93,9 @@ struct rcu_dynticks {
93#define RCU_KTHREAD_STOPPED 0 93#define RCU_KTHREAD_STOPPED 0
94#define RCU_KTHREAD_RUNNING 1 94#define RCU_KTHREAD_RUNNING 1
95#define RCU_KTHREAD_WAITING 2 95#define RCU_KTHREAD_WAITING 2
96#define RCU_KTHREAD_YIELDING 3 96#define RCU_KTHREAD_OFFCPU 3
97#define RCU_KTHREAD_MAX 3 97#define RCU_KTHREAD_YIELDING 4
98#define RCU_KTHREAD_MAX 4
98 99
99/* 100/*
100 * Definition for node within the RCU grace-period-detection hierarchy. 101 * Definition for node within the RCU grace-period-detection hierarchy.
@@ -383,6 +384,8 @@ struct rcu_state {
383 /* but in jiffies. */ 384 /* but in jiffies. */
384 unsigned long jiffies_stall; /* Time at which to check */ 385 unsigned long jiffies_stall; /* Time at which to check */
385 /* for CPU stalls. */ 386 /* for CPU stalls. */
387 unsigned long gp_max; /* Maximum GP duration in */
388 /* jiffies. */
386 char *name; /* Name of structure. */ 389 char *name; /* Name of structure. */
387}; 390};
388 391
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index 3baa235786b5..564b8fef2a7e 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -47,13 +47,14 @@
47#include "rcutree.h" 47#include "rcutree.h"
48 48
49DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status); 49DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
50DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_cpu);
50DECLARE_PER_CPU(char, rcu_cpu_has_work); 51DECLARE_PER_CPU(char, rcu_cpu_has_work);
51 52
52static char convert_kthread_status(unsigned int kthread_status) 53static char convert_kthread_status(unsigned int kthread_status)
53{ 54{
54 if (kthread_status > RCU_KTHREAD_MAX) 55 if (kthread_status > RCU_KTHREAD_MAX)
55 return '?'; 56 return '?';
56 return "SRWY"[kthread_status]; 57 return "SRWOY"[kthread_status];
57} 58}
58 59
59static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) 60static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
@@ -74,7 +75,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
74 rdp->dynticks_fqs); 75 rdp->dynticks_fqs);
75#endif /* #ifdef CONFIG_NO_HZ */ 76#endif /* #ifdef CONFIG_NO_HZ */
76 seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); 77 seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
77 seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c b=%ld", 78 seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c/%d b=%ld",
78 rdp->qlen, 79 rdp->qlen,
79 ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != 80 ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
80 rdp->nxttail[RCU_NEXT_TAIL]], 81 rdp->nxttail[RCU_NEXT_TAIL]],
@@ -86,6 +87,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
86 per_cpu(rcu_cpu_has_work, rdp->cpu), 87 per_cpu(rcu_cpu_has_work, rdp->cpu),
87 convert_kthread_status(per_cpu(rcu_cpu_kthread_status, 88 convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
88 rdp->cpu)), 89 rdp->cpu)),
90 per_cpu(rcu_cpu_kthread_cpu, rdp->cpu),
89 rdp->blimit); 91 rdp->blimit);
90 seq_printf(m, " ci=%lu co=%lu ca=%lu\n", 92 seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
91 rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); 93 rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
@@ -312,16 +314,35 @@ static const struct file_operations rcuhier_fops = {
312 .release = single_release, 314 .release = single_release,
313}; 315};
314 316
317static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)
318{
319 unsigned long flags;
320 unsigned long completed;
321 unsigned long gpnum;
322 unsigned long gpage;
323 unsigned long gpmax;
324 struct rcu_node *rnp = &rsp->node[0];
325
326 raw_spin_lock_irqsave(&rnp->lock, flags);
327 completed = rsp->completed;
328 gpnum = rsp->gpnum;
329 if (rsp->completed == rsp->gpnum)
330 gpage = 0;
331 else
332 gpage = jiffies - rsp->gp_start;
333 gpmax = rsp->gp_max;
334 raw_spin_unlock_irqrestore(&rnp->lock, flags);
335 seq_printf(m, "%s: completed=%ld gpnum=%lu age=%ld max=%ld\n",
336 rsp->name, completed, gpnum, gpage, gpmax);
337}
338
315static int show_rcugp(struct seq_file *m, void *unused) 339static int show_rcugp(struct seq_file *m, void *unused)
316{ 340{
317#ifdef CONFIG_TREE_PREEMPT_RCU 341#ifdef CONFIG_TREE_PREEMPT_RCU
318 seq_printf(m, "rcu_preempt: completed=%ld gpnum=%lu\n", 342 show_one_rcugp(m, &rcu_preempt_state);
319 rcu_preempt_state.completed, rcu_preempt_state.gpnum);
320#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ 343#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
321 seq_printf(m, "rcu_sched: completed=%ld gpnum=%lu\n", 344 show_one_rcugp(m, &rcu_sched_state);
322 rcu_sched_state.completed, rcu_sched_state.gpnum); 345 show_one_rcugp(m, &rcu_bh_state);
323 seq_printf(m, "rcu_bh: completed=%ld gpnum=%lu\n",
324 rcu_bh_state.completed, rcu_bh_state.gpnum);
325 return 0; 346 return 0;
326} 347}
327 348