aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/lockdep.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2010-04-05 18:10:17 -0400
committerIngo Molnar <mingo@elte.hu>2010-04-05 18:15:37 -0400
commitbd6d29c25bb1a24a4c160ec5de43e0004e01f72b (patch)
tree0aa96c7e9fdfbe7dc9c7e40151aed928903240f0 /kernel/lockdep.c
parentced918eb748ce30b3aace549fd17540e40ffdca0 (diff)
lockstat: Make lockstat counting per cpu
Locking statistics are implemented using global atomic variables. This is usually fine unless some path write them very often. This is the case for the function and function graph tracers that disable irqs for each entry saved (except if the function tracer is in preempt disabled only mode). And calls to local_irq_save/restore() increment hardirqs_on_events and hardirqs_off_events stats (or similar stats for redundant versions). Incrementing these global vars for each function ends up in too much cache bouncing if lockstats are enabled. To solve this, implement the debug_atomic_*() operations using per cpu vars. -v2: Use per_cpu() instead of get_cpu_var() to fetch the desired cpu vars on debug_atomic_read() -v3: Store the stats in a structure. No need for local_t as we are NMI/irq safe. -v4: Fix tons of build errors. I thought I had tested it but I probably forgot to select the relevant config. Suggested-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <1270505417-8144-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/lockdep.c')
-rw-r--r--kernel/lockdep.c47
1 files changed, 17 insertions, 30 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 0c30d0455de1..069af0276bf7 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -430,20 +430,7 @@ static struct stack_trace lockdep_init_trace = {
430/* 430/*
431 * Various lockdep statistics: 431 * Various lockdep statistics:
432 */ 432 */
433atomic_t chain_lookup_hits; 433DEFINE_PER_CPU(struct lockdep_stats, lockdep_stats);
434atomic_t chain_lookup_misses;
435atomic_t hardirqs_on_events;
436atomic_t hardirqs_off_events;
437atomic_t redundant_hardirqs_on;
438atomic_t redundant_hardirqs_off;
439atomic_t softirqs_on_events;
440atomic_t softirqs_off_events;
441atomic_t redundant_softirqs_on;
442atomic_t redundant_softirqs_off;
443atomic_t nr_unused_locks;
444atomic_t nr_cyclic_checks;
445atomic_t nr_find_usage_forwards_checks;
446atomic_t nr_find_usage_backwards_checks;
447#endif 434#endif
448 435
449/* 436/*
@@ -758,7 +745,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
758 return NULL; 745 return NULL;
759 } 746 }
760 class = lock_classes + nr_lock_classes++; 747 class = lock_classes + nr_lock_classes++;
761 debug_atomic_inc(&nr_unused_locks); 748 debug_atomic_inc(nr_unused_locks);
762 class->key = key; 749 class->key = key;
763 class->name = lock->name; 750 class->name = lock->name;
764 class->subclass = subclass; 751 class->subclass = subclass;
@@ -1215,7 +1202,7 @@ check_noncircular(struct lock_list *root, struct lock_class *target,
1215{ 1202{
1216 int result; 1203 int result;
1217 1204
1218 debug_atomic_inc(&nr_cyclic_checks); 1205 debug_atomic_inc(nr_cyclic_checks);
1219 1206
1220 result = __bfs_forwards(root, target, class_equal, target_entry); 1207 result = __bfs_forwards(root, target, class_equal, target_entry);
1221 1208
@@ -1252,7 +1239,7 @@ find_usage_forwards(struct lock_list *root, enum lock_usage_bit bit,
1252{ 1239{
1253 int result; 1240 int result;
1254 1241
1255 debug_atomic_inc(&nr_find_usage_forwards_checks); 1242 debug_atomic_inc(nr_find_usage_forwards_checks);
1256 1243
1257 result = __bfs_forwards(root, (void *)bit, usage_match, target_entry); 1244 result = __bfs_forwards(root, (void *)bit, usage_match, target_entry);
1258 1245
@@ -1275,7 +1262,7 @@ find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit,
1275{ 1262{
1276 int result; 1263 int result;
1277 1264
1278 debug_atomic_inc(&nr_find_usage_backwards_checks); 1265 debug_atomic_inc(nr_find_usage_backwards_checks);
1279 1266
1280 result = __bfs_backwards(root, (void *)bit, usage_match, target_entry); 1267 result = __bfs_backwards(root, (void *)bit, usage_match, target_entry);
1281 1268
@@ -1835,7 +1822,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
1835 list_for_each_entry(chain, hash_head, entry) { 1822 list_for_each_entry(chain, hash_head, entry) {
1836 if (chain->chain_key == chain_key) { 1823 if (chain->chain_key == chain_key) {
1837cache_hit: 1824cache_hit:
1838 debug_atomic_inc(&chain_lookup_hits); 1825 debug_atomic_inc(chain_lookup_hits);
1839 if (very_verbose(class)) 1826 if (very_verbose(class))
1840 printk("\nhash chain already cached, key: " 1827 printk("\nhash chain already cached, key: "
1841 "%016Lx tail class: [%p] %s\n", 1828 "%016Lx tail class: [%p] %s\n",
@@ -1900,7 +1887,7 @@ cache_hit:
1900 chain_hlocks[chain->base + j] = class - lock_classes; 1887 chain_hlocks[chain->base + j] = class - lock_classes;
1901 } 1888 }
1902 list_add_tail_rcu(&chain->entry, hash_head); 1889 list_add_tail_rcu(&chain->entry, hash_head);
1903 debug_atomic_inc(&chain_lookup_misses); 1890 debug_atomic_inc(chain_lookup_misses);
1904 inc_chains(); 1891 inc_chains();
1905 1892
1906 return 1; 1893 return 1;
@@ -2321,7 +2308,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
2321 return; 2308 return;
2322 2309
2323 if (unlikely(curr->hardirqs_enabled)) { 2310 if (unlikely(curr->hardirqs_enabled)) {
2324 debug_atomic_inc(&redundant_hardirqs_on); 2311 debug_atomic_inc(redundant_hardirqs_on);
2325 return; 2312 return;
2326 } 2313 }
2327 /* we'll do an OFF -> ON transition: */ 2314 /* we'll do an OFF -> ON transition: */
@@ -2348,7 +2335,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
2348 2335
2349 curr->hardirq_enable_ip = ip; 2336 curr->hardirq_enable_ip = ip;
2350 curr->hardirq_enable_event = ++curr->irq_events; 2337 curr->hardirq_enable_event = ++curr->irq_events;
2351 debug_atomic_inc(&hardirqs_on_events); 2338 debug_atomic_inc(hardirqs_on_events);
2352} 2339}
2353EXPORT_SYMBOL(trace_hardirqs_on_caller); 2340EXPORT_SYMBOL(trace_hardirqs_on_caller);
2354 2341
@@ -2380,9 +2367,9 @@ void trace_hardirqs_off_caller(unsigned long ip)
2380 curr->hardirqs_enabled = 0; 2367 curr->hardirqs_enabled = 0;
2381 curr->hardirq_disable_ip = ip; 2368 curr->hardirq_disable_ip = ip;
2382 curr->hardirq_disable_event = ++curr->irq_events; 2369 curr->hardirq_disable_event = ++curr->irq_events;
2383 debug_atomic_inc(&hardirqs_off_events); 2370 debug_atomic_inc(hardirqs_off_events);
2384 } else 2371 } else
2385 debug_atomic_inc(&redundant_hardirqs_off); 2372 debug_atomic_inc(redundant_hardirqs_off);
2386} 2373}
2387EXPORT_SYMBOL(trace_hardirqs_off_caller); 2374EXPORT_SYMBOL(trace_hardirqs_off_caller);
2388 2375
@@ -2406,7 +2393,7 @@ void trace_softirqs_on(unsigned long ip)
2406 return; 2393 return;
2407 2394
2408 if (curr->softirqs_enabled) { 2395 if (curr->softirqs_enabled) {
2409 debug_atomic_inc(&redundant_softirqs_on); 2396 debug_atomic_inc(redundant_softirqs_on);
2410 return; 2397 return;
2411 } 2398 }
2412 2399
@@ -2416,7 +2403,7 @@ void trace_softirqs_on(unsigned long ip)
2416 curr->softirqs_enabled = 1; 2403 curr->softirqs_enabled = 1;
2417 curr->softirq_enable_ip = ip; 2404 curr->softirq_enable_ip = ip;
2418 curr->softirq_enable_event = ++curr->irq_events; 2405 curr->softirq_enable_event = ++curr->irq_events;
2419 debug_atomic_inc(&softirqs_on_events); 2406 debug_atomic_inc(softirqs_on_events);
2420 /* 2407 /*
2421 * We are going to turn softirqs on, so set the 2408 * We are going to turn softirqs on, so set the
2422 * usage bit for all held locks, if hardirqs are 2409 * usage bit for all held locks, if hardirqs are
@@ -2446,10 +2433,10 @@ void trace_softirqs_off(unsigned long ip)
2446 curr->softirqs_enabled = 0; 2433 curr->softirqs_enabled = 0;
2447 curr->softirq_disable_ip = ip; 2434 curr->softirq_disable_ip = ip;
2448 curr->softirq_disable_event = ++curr->irq_events; 2435 curr->softirq_disable_event = ++curr->irq_events;
2449 debug_atomic_inc(&softirqs_off_events); 2436 debug_atomic_inc(softirqs_off_events);
2450 DEBUG_LOCKS_WARN_ON(!softirq_count()); 2437 DEBUG_LOCKS_WARN_ON(!softirq_count());
2451 } else 2438 } else
2452 debug_atomic_inc(&redundant_softirqs_off); 2439 debug_atomic_inc(redundant_softirqs_off);
2453} 2440}
2454 2441
2455static void __lockdep_trace_alloc(gfp_t gfp_mask, unsigned long flags) 2442static void __lockdep_trace_alloc(gfp_t gfp_mask, unsigned long flags)
@@ -2654,7 +2641,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
2654 return 0; 2641 return 0;
2655 break; 2642 break;
2656 case LOCK_USED: 2643 case LOCK_USED:
2657 debug_atomic_dec(&nr_unused_locks); 2644 debug_atomic_dec(nr_unused_locks);
2658 break; 2645 break;
2659 default: 2646 default:
2660 if (!debug_locks_off_graph_unlock()) 2647 if (!debug_locks_off_graph_unlock())
@@ -2760,7 +2747,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
2760 if (!class) 2747 if (!class)
2761 return 0; 2748 return 0;
2762 } 2749 }
2763 debug_atomic_inc((atomic_t *)&class->ops); 2750 atomic_inc((atomic_t *)&class->ops);
2764 if (very_verbose(class)) { 2751 if (very_verbose(class)) {
2765 printk("\nacquire class [%p] %s", class->key, class->name); 2752 printk("\nacquire class [%p] %s", class->key, class->name);
2766 if (class->name_version > 1) 2753 if (class->name_version > 1)