diff options
Diffstat (limited to 'kernel/sched_debug.c')
-rw-r--r-- | kernel/sched_debug.c | 127 |
1 files changed, 75 insertions, 52 deletions
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c index 2e1b0d17dd9b..a6710a112b4f 100644 --- a/kernel/sched_debug.c +++ b/kernel/sched_debug.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/kallsyms.h> | 16 | #include <linux/kallsyms.h> |
17 | #include <linux/utsname.h> | 17 | #include <linux/utsname.h> |
18 | 18 | ||
19 | static DEFINE_SPINLOCK(sched_debug_lock); | ||
20 | |||
19 | /* | 21 | /* |
20 | * This allows printing both to /proc/sched_debug and | 22 | * This allows printing both to /proc/sched_debug and |
21 | * to the console | 23 | * to the console |
@@ -54,8 +56,7 @@ static unsigned long nsec_low(unsigned long long nsec) | |||
54 | #define SPLIT_NS(x) nsec_high(x), nsec_low(x) | 56 | #define SPLIT_NS(x) nsec_high(x), nsec_low(x) |
55 | 57 | ||
56 | #ifdef CONFIG_FAIR_GROUP_SCHED | 58 | #ifdef CONFIG_FAIR_GROUP_SCHED |
57 | static void print_cfs_group_stats(struct seq_file *m, int cpu, | 59 | static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group *tg) |
58 | struct task_group *tg) | ||
59 | { | 60 | { |
60 | struct sched_entity *se = tg->se[cpu]; | 61 | struct sched_entity *se = tg->se[cpu]; |
61 | if (!se) | 62 | if (!se) |
@@ -87,6 +88,26 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, | |||
87 | } | 88 | } |
88 | #endif | 89 | #endif |
89 | 90 | ||
91 | #ifdef CONFIG_CGROUP_SCHED | ||
92 | static char group_path[PATH_MAX]; | ||
93 | |||
94 | static char *task_group_path(struct task_group *tg) | ||
95 | { | ||
96 | if (autogroup_path(tg, group_path, PATH_MAX)) | ||
97 | return group_path; | ||
98 | |||
99 | /* | ||
100 | * May be NULL if the underlying cgroup isn't fully-created yet | ||
101 | */ | ||
102 | if (!tg->css.cgroup) { | ||
103 | group_path[0] = '\0'; | ||
104 | return group_path; | ||
105 | } | ||
106 | cgroup_path(tg->css.cgroup, group_path, PATH_MAX); | ||
107 | return group_path; | ||
108 | } | ||
109 | #endif | ||
110 | |||
90 | static void | 111 | static void |
91 | print_task(struct seq_file *m, struct rq *rq, struct task_struct *p) | 112 | print_task(struct seq_file *m, struct rq *rq, struct task_struct *p) |
92 | { | 113 | { |
@@ -109,17 +130,10 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p) | |||
109 | SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld", | 130 | SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld", |
110 | 0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L); | 131 | 0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L); |
111 | #endif | 132 | #endif |
112 | |||
113 | #ifdef CONFIG_CGROUP_SCHED | 133 | #ifdef CONFIG_CGROUP_SCHED |
114 | { | 134 | SEQ_printf(m, " %s", task_group_path(task_group(p))); |
115 | char path[64]; | ||
116 | |||
117 | rcu_read_lock(); | ||
118 | cgroup_path(task_group(p)->css.cgroup, path, sizeof(path)); | ||
119 | rcu_read_unlock(); | ||
120 | SEQ_printf(m, " %s", path); | ||
121 | } | ||
122 | #endif | 135 | #endif |
136 | |||
123 | SEQ_printf(m, "\n"); | 137 | SEQ_printf(m, "\n"); |
124 | } | 138 | } |
125 | 139 | ||
@@ -138,7 +152,7 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu) | |||
138 | read_lock_irqsave(&tasklist_lock, flags); | 152 | read_lock_irqsave(&tasklist_lock, flags); |
139 | 153 | ||
140 | do_each_thread(g, p) { | 154 | do_each_thread(g, p) { |
141 | if (!p->se.on_rq || task_cpu(p) != rq_cpu) | 155 | if (!p->on_rq || task_cpu(p) != rq_cpu) |
142 | continue; | 156 | continue; |
143 | 157 | ||
144 | print_task(m, rq, p); | 158 | print_task(m, rq, p); |
@@ -147,19 +161,6 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu) | |||
147 | read_unlock_irqrestore(&tasklist_lock, flags); | 161 | read_unlock_irqrestore(&tasklist_lock, flags); |
148 | } | 162 | } |
149 | 163 | ||
150 | #if defined(CONFIG_CGROUP_SCHED) && \ | ||
151 | (defined(CONFIG_FAIR_GROUP_SCHED) || defined(CONFIG_RT_GROUP_SCHED)) | ||
152 | static void task_group_path(struct task_group *tg, char *buf, int buflen) | ||
153 | { | ||
154 | /* may be NULL if the underlying cgroup isn't fully-created yet */ | ||
155 | if (!tg->css.cgroup) { | ||
156 | buf[0] = '\0'; | ||
157 | return; | ||
158 | } | ||
159 | cgroup_path(tg->css.cgroup, buf, buflen); | ||
160 | } | ||
161 | #endif | ||
162 | |||
163 | void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | 164 | void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) |
164 | { | 165 | { |
165 | s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1, | 166 | s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1, |
@@ -168,13 +169,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | |||
168 | struct sched_entity *last; | 169 | struct sched_entity *last; |
169 | unsigned long flags; | 170 | unsigned long flags; |
170 | 171 | ||
171 | #if defined(CONFIG_CGROUP_SCHED) && defined(CONFIG_FAIR_GROUP_SCHED) | 172 | #ifdef CONFIG_FAIR_GROUP_SCHED |
172 | char path[128]; | 173 | SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg)); |
173 | struct task_group *tg = cfs_rq->tg; | ||
174 | |||
175 | task_group_path(tg, path, sizeof(path)); | ||
176 | |||
177 | SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, path); | ||
178 | #else | 174 | #else |
179 | SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu); | 175 | SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu); |
180 | #endif | 176 | #endif |
@@ -183,7 +179,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | |||
183 | 179 | ||
184 | raw_spin_lock_irqsave(&rq->lock, flags); | 180 | raw_spin_lock_irqsave(&rq->lock, flags); |
185 | if (cfs_rq->rb_leftmost) | 181 | if (cfs_rq->rb_leftmost) |
186 | MIN_vruntime = (__pick_next_entity(cfs_rq))->vruntime; | 182 | MIN_vruntime = (__pick_first_entity(cfs_rq))->vruntime; |
187 | last = __pick_last_entity(cfs_rq); | 183 | last = __pick_last_entity(cfs_rq); |
188 | if (last) | 184 | if (last) |
189 | max_vruntime = last->vruntime; | 185 | max_vruntime = last->vruntime; |
@@ -202,33 +198,34 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | |||
202 | spread0 = min_vruntime - rq0_min_vruntime; | 198 | spread0 = min_vruntime - rq0_min_vruntime; |
203 | SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "spread0", | 199 | SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "spread0", |
204 | SPLIT_NS(spread0)); | 200 | SPLIT_NS(spread0)); |
205 | SEQ_printf(m, " .%-30s: %ld\n", "nr_running", cfs_rq->nr_running); | ||
206 | SEQ_printf(m, " .%-30s: %ld\n", "load", cfs_rq->load.weight); | ||
207 | |||
208 | SEQ_printf(m, " .%-30s: %d\n", "nr_spread_over", | 201 | SEQ_printf(m, " .%-30s: %d\n", "nr_spread_over", |
209 | cfs_rq->nr_spread_over); | 202 | cfs_rq->nr_spread_over); |
203 | SEQ_printf(m, " .%-30s: %ld\n", "nr_running", cfs_rq->nr_running); | ||
204 | SEQ_printf(m, " .%-30s: %ld\n", "load", cfs_rq->load.weight); | ||
210 | #ifdef CONFIG_FAIR_GROUP_SCHED | 205 | #ifdef CONFIG_FAIR_GROUP_SCHED |
211 | #ifdef CONFIG_SMP | 206 | #ifdef CONFIG_SMP |
212 | SEQ_printf(m, " .%-30s: %lu\n", "shares", cfs_rq->shares); | 207 | SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "load_avg", |
208 | SPLIT_NS(cfs_rq->load_avg)); | ||
209 | SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "load_period", | ||
210 | SPLIT_NS(cfs_rq->load_period)); | ||
211 | SEQ_printf(m, " .%-30s: %ld\n", "load_contrib", | ||
212 | cfs_rq->load_contribution); | ||
213 | SEQ_printf(m, " .%-30s: %d\n", "load_tg", | ||
214 | atomic_read(&cfs_rq->tg->load_weight)); | ||
213 | #endif | 215 | #endif |
216 | |||
214 | print_cfs_group_stats(m, cpu, cfs_rq->tg); | 217 | print_cfs_group_stats(m, cpu, cfs_rq->tg); |
215 | #endif | 218 | #endif |
216 | } | 219 | } |
217 | 220 | ||
218 | void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) | 221 | void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) |
219 | { | 222 | { |
220 | #if defined(CONFIG_CGROUP_SCHED) && defined(CONFIG_RT_GROUP_SCHED) | 223 | #ifdef CONFIG_RT_GROUP_SCHED |
221 | char path[128]; | 224 | SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg)); |
222 | struct task_group *tg = rt_rq->tg; | ||
223 | |||
224 | task_group_path(tg, path, sizeof(path)); | ||
225 | |||
226 | SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, path); | ||
227 | #else | 225 | #else |
228 | SEQ_printf(m, "\nrt_rq[%d]:\n", cpu); | 226 | SEQ_printf(m, "\nrt_rq[%d]:\n", cpu); |
229 | #endif | 227 | #endif |
230 | 228 | ||
231 | |||
232 | #define P(x) \ | 229 | #define P(x) \ |
233 | SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x)) | 230 | SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x)) |
234 | #define PN(x) \ | 231 | #define PN(x) \ |
@@ -243,9 +240,12 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) | |||
243 | #undef P | 240 | #undef P |
244 | } | 241 | } |
245 | 242 | ||
243 | extern __read_mostly int sched_clock_running; | ||
244 | |||
246 | static void print_cpu(struct seq_file *m, int cpu) | 245 | static void print_cpu(struct seq_file *m, int cpu) |
247 | { | 246 | { |
248 | struct rq *rq = cpu_rq(cpu); | 247 | struct rq *rq = cpu_rq(cpu); |
248 | unsigned long flags; | ||
249 | 249 | ||
250 | #ifdef CONFIG_X86 | 250 | #ifdef CONFIG_X86 |
251 | { | 251 | { |
@@ -296,14 +296,17 @@ static void print_cpu(struct seq_file *m, int cpu) | |||
296 | P(ttwu_count); | 296 | P(ttwu_count); |
297 | P(ttwu_local); | 297 | P(ttwu_local); |
298 | 298 | ||
299 | P(bkl_count); | ||
300 | |||
301 | #undef P | 299 | #undef P |
300 | #undef P64 | ||
302 | #endif | 301 | #endif |
302 | spin_lock_irqsave(&sched_debug_lock, flags); | ||
303 | print_cfs_stats(m, cpu); | 303 | print_cfs_stats(m, cpu); |
304 | print_rt_stats(m, cpu); | 304 | print_rt_stats(m, cpu); |
305 | 305 | ||
306 | rcu_read_lock(); | ||
306 | print_rq(m, rq, cpu); | 307 | print_rq(m, rq, cpu); |
308 | rcu_read_unlock(); | ||
309 | spin_unlock_irqrestore(&sched_debug_lock, flags); | ||
307 | } | 310 | } |
308 | 311 | ||
309 | static const char *sched_tunable_scaling_names[] = { | 312 | static const char *sched_tunable_scaling_names[] = { |
@@ -314,21 +317,42 @@ static const char *sched_tunable_scaling_names[] = { | |||
314 | 317 | ||
315 | static int sched_debug_show(struct seq_file *m, void *v) | 318 | static int sched_debug_show(struct seq_file *m, void *v) |
316 | { | 319 | { |
317 | u64 now = ktime_to_ns(ktime_get()); | 320 | u64 ktime, sched_clk, cpu_clk; |
321 | unsigned long flags; | ||
318 | int cpu; | 322 | int cpu; |
319 | 323 | ||
320 | SEQ_printf(m, "Sched Debug Version: v0.09, %s %.*s\n", | 324 | local_irq_save(flags); |
325 | ktime = ktime_to_ns(ktime_get()); | ||
326 | sched_clk = sched_clock(); | ||
327 | cpu_clk = local_clock(); | ||
328 | local_irq_restore(flags); | ||
329 | |||
330 | SEQ_printf(m, "Sched Debug Version: v0.10, %s %.*s\n", | ||
321 | init_utsname()->release, | 331 | init_utsname()->release, |
322 | (int)strcspn(init_utsname()->version, " "), | 332 | (int)strcspn(init_utsname()->version, " "), |
323 | init_utsname()->version); | 333 | init_utsname()->version); |
324 | 334 | ||
325 | SEQ_printf(m, "now at %Lu.%06ld msecs\n", SPLIT_NS(now)); | 335 | #define P(x) \ |
336 | SEQ_printf(m, "%-40s: %Ld\n", #x, (long long)(x)) | ||
337 | #define PN(x) \ | ||
338 | SEQ_printf(m, "%-40s: %Ld.%06ld\n", #x, SPLIT_NS(x)) | ||
339 | PN(ktime); | ||
340 | PN(sched_clk); | ||
341 | PN(cpu_clk); | ||
342 | P(jiffies); | ||
343 | #ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK | ||
344 | P(sched_clock_stable); | ||
345 | #endif | ||
346 | #undef PN | ||
347 | #undef P | ||
348 | |||
349 | SEQ_printf(m, "\n"); | ||
350 | SEQ_printf(m, "sysctl_sched\n"); | ||
326 | 351 | ||
327 | #define P(x) \ | 352 | #define P(x) \ |
328 | SEQ_printf(m, " .%-40s: %Ld\n", #x, (long long)(x)) | 353 | SEQ_printf(m, " .%-40s: %Ld\n", #x, (long long)(x)) |
329 | #define PN(x) \ | 354 | #define PN(x) \ |
330 | SEQ_printf(m, " .%-40s: %Ld.%06ld\n", #x, SPLIT_NS(x)) | 355 | SEQ_printf(m, " .%-40s: %Ld.%06ld\n", #x, SPLIT_NS(x)) |
331 | P(jiffies); | ||
332 | PN(sysctl_sched_latency); | 356 | PN(sysctl_sched_latency); |
333 | PN(sysctl_sched_min_granularity); | 357 | PN(sysctl_sched_min_granularity); |
334 | PN(sysctl_sched_wakeup_granularity); | 358 | PN(sysctl_sched_wakeup_granularity); |
@@ -414,7 +438,6 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m) | |||
414 | P(se.statistics.wait_count); | 438 | P(se.statistics.wait_count); |
415 | PN(se.statistics.iowait_sum); | 439 | PN(se.statistics.iowait_sum); |
416 | P(se.statistics.iowait_count); | 440 | P(se.statistics.iowait_count); |
417 | P(sched_info.bkl_count); | ||
418 | P(se.nr_migrations); | 441 | P(se.nr_migrations); |
419 | P(se.statistics.nr_migrations_cold); | 442 | P(se.statistics.nr_migrations_cold); |
420 | P(se.statistics.nr_failed_migrations_affine); | 443 | P(se.statistics.nr_failed_migrations_affine); |