diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2012-01-16 16:29:10 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2012-02-21 12:03:49 -0500 |
commit | a858af2875fb291d0f4b0a4419fefbf03c2379c0 (patch) | |
tree | 5183796cbf50ec0cd3bd5c741db15705376dacbd /kernel/rcutree_plugin.h | |
parent | 13cfcca0e4e2d4cee1d0183c049eb34e54ac976e (diff) |
rcu: Print scheduling-clock information on RCU CPU stall-warning messages
There have been situations where RCU CPU stall warnings were caused by
issues in scheduling-clock timer initialization. To make it easier to
track these down, this commit causes the RCU CPU stall-warning messages
to print out the number of scheduling-clock interrupts taken in the
current grace period for each stalled CPU.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutree_plugin.h')
-rw-r--r-- | kernel/rcutree_plugin.h | 150 |
1 files changed, 147 insertions, 3 deletions
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 0e74e1c6333f..aa93b074bb2f 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -63,7 +63,10 @@ static void __init rcu_bootup_announce_oddness(void) | |||
63 | printk(KERN_INFO "\tRCU torture testing starts during boot.\n"); | 63 | printk(KERN_INFO "\tRCU torture testing starts during boot.\n"); |
64 | #endif | 64 | #endif |
65 | #if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE) | 65 | #if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE) |
66 | printk(KERN_INFO "\tVerbose stalled-CPUs detection is disabled.\n"); | 66 | printk(KERN_INFO "\tDump stacks of tasks blocking RCU-preempt GP.\n"); |
67 | #endif | ||
68 | #if defined(CONFIG_RCU_CPU_STALL_INFO) | ||
69 | printk(KERN_INFO "\tAdditional per-CPU info printed with stalls.\n"); | ||
67 | #endif | 70 | #endif |
68 | #if NUM_RCU_LVL_4 != 0 | 71 | #if NUM_RCU_LVL_4 != 0 |
69 | printk(KERN_INFO "\tExperimental four-level hierarchy is enabled.\n"); | 72 | printk(KERN_INFO "\tExperimental four-level hierarchy is enabled.\n"); |
@@ -490,6 +493,31 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp) | |||
490 | 493 | ||
491 | #endif /* #else #ifdef CONFIG_RCU_CPU_STALL_VERBOSE */ | 494 | #endif /* #else #ifdef CONFIG_RCU_CPU_STALL_VERBOSE */ |
492 | 495 | ||
496 | #ifdef CONFIG_RCU_CPU_STALL_INFO | ||
497 | |||
498 | static void rcu_print_task_stall_begin(struct rcu_node *rnp) | ||
499 | { | ||
500 | printk(KERN_ERR "\tTasks blocked on level-%d rcu_node (CPUs %d-%d):", | ||
501 | rnp->level, rnp->grplo, rnp->grphi); | ||
502 | } | ||
503 | |||
504 | static void rcu_print_task_stall_end(void) | ||
505 | { | ||
506 | printk(KERN_CONT "\n"); | ||
507 | } | ||
508 | |||
509 | #else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */ | ||
510 | |||
511 | static void rcu_print_task_stall_begin(struct rcu_node *rnp) | ||
512 | { | ||
513 | } | ||
514 | |||
515 | static void rcu_print_task_stall_end(void) | ||
516 | { | ||
517 | } | ||
518 | |||
519 | #endif /* #else #ifdef CONFIG_RCU_CPU_STALL_INFO */ | ||
520 | |||
493 | /* | 521 | /* |
494 | * Scan the current list of tasks blocked within RCU read-side critical | 522 | * Scan the current list of tasks blocked within RCU read-side critical |
495 | * sections, printing out the tid of each. | 523 | * sections, printing out the tid of each. |
@@ -501,12 +529,14 @@ static int rcu_print_task_stall(struct rcu_node *rnp) | |||
501 | 529 | ||
502 | if (!rcu_preempt_blocked_readers_cgp(rnp)) | 530 | if (!rcu_preempt_blocked_readers_cgp(rnp)) |
503 | return 0; | 531 | return 0; |
532 | rcu_print_task_stall_begin(rnp); | ||
504 | t = list_entry(rnp->gp_tasks, | 533 | t = list_entry(rnp->gp_tasks, |
505 | struct task_struct, rcu_node_entry); | 534 | struct task_struct, rcu_node_entry); |
506 | list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) { | 535 | list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) { |
507 | printk(" P%d", t->pid); | 536 | printk(KERN_CONT " P%d", t->pid); |
508 | ndetected++; | 537 | ndetected++; |
509 | } | 538 | } |
539 | rcu_print_task_stall_end(); | ||
510 | return ndetected; | 540 | return ndetected; |
511 | } | 541 | } |
512 | 542 | ||
@@ -2004,7 +2034,7 @@ static void rcu_cleanup_after_idle(int cpu) | |||
2004 | } | 2034 | } |
2005 | 2035 | ||
2006 | /* | 2036 | /* |
2007 | * Do the idle-entry grace-period work, which, because CONFIG_RCU_FAST_NO_HZ=y, | 2037 | * Do the idle-entry grace-period work, which, because CONFIG_RCU_FAST_NO_HZ=n, |
2008 | * is nothing. | 2038 | * is nothing. |
2009 | */ | 2039 | */ |
2010 | static void rcu_prepare_for_idle(int cpu) | 2040 | static void rcu_prepare_for_idle(int cpu) |
@@ -2273,3 +2303,117 @@ static void rcu_prepare_for_idle(int cpu) | |||
2273 | } | 2303 | } |
2274 | 2304 | ||
2275 | #endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */ | 2305 | #endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */ |
2306 | |||
2307 | #ifdef CONFIG_RCU_CPU_STALL_INFO | ||
2308 | |||
2309 | #ifdef CONFIG_RCU_FAST_NO_HZ | ||
2310 | |||
2311 | static void print_cpu_stall_fast_no_hz(char *cp, int cpu) | ||
2312 | { | ||
2313 | struct hrtimer *hrtp = &per_cpu(rcu_idle_gp_timer, cpu); | ||
2314 | |||
2315 | sprintf(cp, "drain=%d %c timer=%lld", | ||
2316 | per_cpu(rcu_dyntick_drain, cpu), | ||
2317 | per_cpu(rcu_dyntick_holdoff, cpu) == jiffies ? 'H' : '.', | ||
2318 | hrtimer_active(hrtp) | ||
2319 | ? ktime_to_us(hrtimer_get_remaining(hrtp)) | ||
2320 | : -1); | ||
2321 | } | ||
2322 | |||
2323 | #else /* #ifdef CONFIG_RCU_FAST_NO_HZ */ | ||
2324 | |||
2325 | static void print_cpu_stall_fast_no_hz(char *cp, int cpu) | ||
2326 | { | ||
2327 | } | ||
2328 | |||
2329 | #endif /* #else #ifdef CONFIG_RCU_FAST_NO_HZ */ | ||
2330 | |||
2331 | /* Initiate the stall-info list. */ | ||
2332 | static void print_cpu_stall_info_begin(void) | ||
2333 | { | ||
2334 | printk(KERN_CONT "\n"); | ||
2335 | } | ||
2336 | |||
2337 | /* | ||
2338 | * Print out diagnostic information for the specified stalled CPU. | ||
2339 | * | ||
2340 | * If the specified CPU is aware of the current RCU grace period | ||
2341 | * (flavor specified by rsp), then print the number of scheduling | ||
2342 | * clock interrupts the CPU has taken during the time that it has | ||
2343 | * been aware. Otherwise, print the number of RCU grace periods | ||
2344 | * that this CPU is ignorant of, for example, "1" if the CPU was | ||
2345 | * aware of the previous grace period. | ||
2346 | * | ||
2347 | * Also print out idle and (if CONFIG_RCU_FAST_NO_HZ) idle-entry info. | ||
2348 | */ | ||
2349 | static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) | ||
2350 | { | ||
2351 | char fast_no_hz[72]; | ||
2352 | struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); | ||
2353 | struct rcu_dynticks *rdtp = rdp->dynticks; | ||
2354 | char *ticks_title; | ||
2355 | unsigned long ticks_value; | ||
2356 | |||
2357 | if (rsp->gpnum == rdp->gpnum) { | ||
2358 | ticks_title = "ticks this GP"; | ||
2359 | ticks_value = rdp->ticks_this_gp; | ||
2360 | } else { | ||
2361 | ticks_title = "GPs behind"; | ||
2362 | ticks_value = rsp->gpnum - rdp->gpnum; | ||
2363 | } | ||
2364 | print_cpu_stall_fast_no_hz(fast_no_hz, cpu); | ||
2365 | printk(KERN_ERR "\t%d: (%lu %s) idle=%03x/%llx/%d %s\n", | ||
2366 | cpu, ticks_value, ticks_title, | ||
2367 | atomic_read(&rdtp->dynticks) & 0xfff, | ||
2368 | rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting, | ||
2369 | fast_no_hz); | ||
2370 | } | ||
2371 | |||
2372 | /* Terminate the stall-info list. */ | ||
2373 | static void print_cpu_stall_info_end(void) | ||
2374 | { | ||
2375 | printk(KERN_ERR "\t"); | ||
2376 | } | ||
2377 | |||
2378 | /* Zero ->ticks_this_gp for all flavors of RCU. */ | ||
2379 | static void zero_cpu_stall_ticks(struct rcu_data *rdp) | ||
2380 | { | ||
2381 | rdp->ticks_this_gp = 0; | ||
2382 | } | ||
2383 | |||
2384 | /* Increment ->ticks_this_gp for all flavors of RCU. */ | ||
2385 | static void increment_cpu_stall_ticks(void) | ||
2386 | { | ||
2387 | __get_cpu_var(rcu_sched_data).ticks_this_gp++; | ||
2388 | __get_cpu_var(rcu_bh_data).ticks_this_gp++; | ||
2389 | #ifdef CONFIG_TREE_PREEMPT_RCU | ||
2390 | __get_cpu_var(rcu_preempt_data).ticks_this_gp++; | ||
2391 | #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ | ||
2392 | } | ||
2393 | |||
2394 | #else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */ | ||
2395 | |||
2396 | static void print_cpu_stall_info_begin(void) | ||
2397 | { | ||
2398 | printk(KERN_CONT " {"); | ||
2399 | } | ||
2400 | |||
2401 | static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) | ||
2402 | { | ||
2403 | printk(KERN_CONT " %d", cpu); | ||
2404 | } | ||
2405 | |||
2406 | static void print_cpu_stall_info_end(void) | ||
2407 | { | ||
2408 | printk(KERN_CONT "} "); | ||
2409 | } | ||
2410 | |||
2411 | static void zero_cpu_stall_ticks(struct rcu_data *rdp) | ||
2412 | { | ||
2413 | } | ||
2414 | |||
2415 | static void increment_cpu_stall_ticks(void) | ||
2416 | { | ||
2417 | } | ||
2418 | |||
2419 | #endif /* #else #ifdef CONFIG_RCU_CPU_STALL_INFO */ | ||