aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2007-07-19 04:49:00 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:49 -0400
commit96645678cd726e87ce42a0664de71e047e32bca4 (patch)
tree116f568a090414777b481e8e5d9db55f420e4335
parent443aef0eddfa44c158d1b94ebb431a70638fcab4 (diff)
lockstat: measure lock bouncing
__acquire | lock _____ | \ | __contended | | | wait | _______/ |/ | __acquired | __release | unlock We measure acquisition and contention bouncing. This is done by recording a cpu stamp in each lock instance. Contention bouncing requires the cpu stamp to be set on acquisition. Hence we move __acquired into the generic path. __acquired is then used to measure acquisition bouncing by comparing the current cpu with the old stamp before replacing it. __contended is used to measure contention bouncing (only useful for preemptable locks) [akpm@linux-foundation.org: cleanups] Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/lockdep.h17
-rw-r--r--kernel/lockdep.c38
-rw-r--r--kernel/lockdep_proc.c19
-rw-r--r--kernel/mutex.c2
4 files changed, 55 insertions, 21 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 3d3386b88b6a..0e843bf65877 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -130,12 +130,24 @@ struct lock_time {
130 unsigned long nr; 130 unsigned long nr;
131}; 131};
132 132
133enum bounce_type {
134 bounce_acquired_write,
135 bounce_acquired_read,
136 bounce_contended_write,
137 bounce_contended_read,
138 nr_bounce_types,
139
140 bounce_acquired = bounce_acquired_write,
141 bounce_contended = bounce_contended_write,
142};
143
133struct lock_class_stats { 144struct lock_class_stats {
134 unsigned long contention_point[4]; 145 unsigned long contention_point[4];
135 struct lock_time read_waittime; 146 struct lock_time read_waittime;
136 struct lock_time write_waittime; 147 struct lock_time write_waittime;
137 struct lock_time read_holdtime; 148 struct lock_time read_holdtime;
138 struct lock_time write_holdtime; 149 struct lock_time write_holdtime;
150 unsigned long bounces[nr_bounce_types];
139}; 151};
140 152
141struct lock_class_stats lock_stats(struct lock_class *class); 153struct lock_class_stats lock_stats(struct lock_class *class);
@@ -150,6 +162,9 @@ struct lockdep_map {
150 struct lock_class_key *key; 162 struct lock_class_key *key;
151 struct lock_class *class_cache; 163 struct lock_class *class_cache;
152 const char *name; 164 const char *name;
165#ifdef CONFIG_LOCK_STAT
166 int cpu;
167#endif
153}; 168};
154 169
155/* 170/*
@@ -321,8 +336,8 @@ do { \
321 if (!try(_lock)) { \ 336 if (!try(_lock)) { \
322 lock_contended(&(_lock)->dep_map, _RET_IP_); \ 337 lock_contended(&(_lock)->dep_map, _RET_IP_); \
323 lock(_lock); \ 338 lock(_lock); \
324 lock_acquired(&(_lock)->dep_map); \
325 } \ 339 } \
340 lock_acquired(&(_lock)->dep_map); \
326} while (0) 341} while (0)
327 342
328#else /* CONFIG_LOCK_STAT */ 343#else /* CONFIG_LOCK_STAT */
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index cb64022851c8..156fce4960c3 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -177,6 +177,9 @@ struct lock_class_stats lock_stats(struct lock_class *class)
177 177
178 lock_time_add(&pcs->read_holdtime, &stats.read_holdtime); 178 lock_time_add(&pcs->read_holdtime, &stats.read_holdtime);
179 lock_time_add(&pcs->write_holdtime, &stats.write_holdtime); 179 lock_time_add(&pcs->write_holdtime, &stats.write_holdtime);
180
181 for (i = 0; i < ARRAY_SIZE(stats.bounces); i++)
182 stats.bounces[i] += pcs->bounces[i];
180 } 183 }
181 184
182 return stats; 185 return stats;
@@ -2325,6 +2328,9 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
2325 lock->name = name; 2328 lock->name = name;
2326 lock->key = key; 2329 lock->key = key;
2327 lock->class_cache = NULL; 2330 lock->class_cache = NULL;
2331#ifdef CONFIG_LOCK_STAT
2332 lock->cpu = raw_smp_processor_id();
2333#endif
2328 if (subclass) 2334 if (subclass)
2329 register_lock_class(lock, subclass, 1); 2335 register_lock_class(lock, subclass, 1);
2330} 2336}
@@ -2775,6 +2781,8 @@ found_it:
2775 stats = get_lock_stats(hlock->class); 2781 stats = get_lock_stats(hlock->class);
2776 if (point < ARRAY_SIZE(stats->contention_point)) 2782 if (point < ARRAY_SIZE(stats->contention_point))
2777 stats->contention_point[i]++; 2783 stats->contention_point[i]++;
2784 if (lock->cpu != smp_processor_id())
2785 stats->bounces[bounce_contended + !!hlock->read]++;
2778 put_lock_stats(stats); 2786 put_lock_stats(stats);
2779} 2787}
2780 2788
@@ -2786,8 +2794,8 @@ __lock_acquired(struct lockdep_map *lock)
2786 struct lock_class_stats *stats; 2794 struct lock_class_stats *stats;
2787 unsigned int depth; 2795 unsigned int depth;
2788 u64 now; 2796 u64 now;
2789 s64 waittime; 2797 s64 waittime = 0;
2790 int i; 2798 int i, cpu;
2791 2799
2792 depth = curr->lockdep_depth; 2800 depth = curr->lockdep_depth;
2793 if (DEBUG_LOCKS_WARN_ON(!depth)) 2801 if (DEBUG_LOCKS_WARN_ON(!depth))
@@ -2809,19 +2817,25 @@ __lock_acquired(struct lockdep_map *lock)
2809 return; 2817 return;
2810 2818
2811found_it: 2819found_it:
2812 if (!hlock->waittime_stamp) 2820 cpu = smp_processor_id();
2813 return; 2821 if (hlock->waittime_stamp) {
2814 2822 now = sched_clock();
2815 now = sched_clock(); 2823 waittime = now - hlock->waittime_stamp;
2816 waittime = now - hlock->waittime_stamp; 2824 hlock->holdtime_stamp = now;
2817 hlock->holdtime_stamp = now; 2825 }
2818 2826
2819 stats = get_lock_stats(hlock->class); 2827 stats = get_lock_stats(hlock->class);
2820 if (hlock->read) 2828 if (waittime) {
2821 lock_time_inc(&stats->read_waittime, waittime); 2829 if (hlock->read)
2822 else 2830 lock_time_inc(&stats->read_waittime, waittime);
2823 lock_time_inc(&stats->write_waittime, waittime); 2831 else
2832 lock_time_inc(&stats->write_waittime, waittime);
2833 }
2834 if (lock->cpu != cpu)
2835 stats->bounces[bounce_acquired + !!hlock->read]++;
2824 put_lock_stats(stats); 2836 put_lock_stats(stats);
2837
2838 lock->cpu = cpu;
2825} 2839}
2826 2840
2827void lock_contended(struct lockdep_map *lock, unsigned long ip) 2841void lock_contended(struct lockdep_map *lock, unsigned long ip)
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c
index 39163ed1bf0a..7ff80135cbeb 100644
--- a/kernel/lockdep_proc.c
+++ b/kernel/lockdep_proc.c
@@ -430,16 +430,18 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
430 else 430 else
431 seq_printf(m, "%40s:", name); 431 seq_printf(m, "%40s:", name);
432 432
433 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]);
433 seq_lock_time(m, &stats->write_waittime); 434 seq_lock_time(m, &stats->write_waittime);
434 seq_puts(m, " "); 435 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]);
435 seq_lock_time(m, &stats->write_holdtime); 436 seq_lock_time(m, &stats->write_holdtime);
436 seq_puts(m, "\n"); 437 seq_puts(m, "\n");
437 } 438 }
438 439
439 if (stats->read_holdtime.nr) { 440 if (stats->read_holdtime.nr) {
440 seq_printf(m, "%38s-R:", name); 441 seq_printf(m, "%38s-R:", name);
442 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]);
441 seq_lock_time(m, &stats->read_waittime); 443 seq_lock_time(m, &stats->read_waittime);
442 seq_puts(m, " "); 444 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]);
443 seq_lock_time(m, &stats->read_holdtime); 445 seq_lock_time(m, &stats->read_holdtime);
444 seq_puts(m, "\n"); 446 seq_puts(m, "\n");
445 } 447 }
@@ -469,26 +471,29 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
469 } 471 }
470 if (i) { 472 if (i) {
471 seq_puts(m, "\n"); 473 seq_puts(m, "\n");
472 seq_line(m, '.', 0, 40 + 1 + 8 * (14 + 1)); 474 seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1));
473 seq_puts(m, "\n"); 475 seq_puts(m, "\n");
474 } 476 }
475} 477}
476 478
477static void seq_header(struct seq_file *m) 479static void seq_header(struct seq_file *m)
478{ 480{
479 seq_printf(m, "lock_stat version 0.1\n"); 481 seq_printf(m, "lock_stat version 0.2\n");
480 seq_line(m, '-', 0, 40 + 1 + 8 * (14 + 1)); 482 seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
481 seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s\n", 483 seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s "
484 "%14s %14s\n",
482 "class name", 485 "class name",
486 "con-bounces",
483 "contentions", 487 "contentions",
484 "waittime-min", 488 "waittime-min",
485 "waittime-max", 489 "waittime-max",
486 "waittime-total", 490 "waittime-total",
491 "acq-bounces",
487 "acquisitions", 492 "acquisitions",
488 "holdtime-min", 493 "holdtime-min",
489 "holdtime-max", 494 "holdtime-max",
490 "holdtime-total"); 495 "holdtime-total");
491 seq_line(m, '-', 0, 40 + 1 + 8 * (14 + 1)); 496 seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
492 seq_printf(m, "\n"); 497 seq_printf(m, "\n");
493} 498}
494 499
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 7a3f32761f26..691b86564dd9 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -180,8 +180,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
180 spin_lock_mutex(&lock->wait_lock, flags); 180 spin_lock_mutex(&lock->wait_lock, flags);
181 } 181 }
182 182
183 lock_acquired(&lock->dep_map);
184done: 183done:
184 lock_acquired(&lock->dep_map);
185 /* got the lock - rejoice! */ 185 /* got the lock - rejoice! */
186 mutex_remove_waiter(lock, &waiter, task_thread_info(task)); 186 mutex_remove_waiter(lock, &waiter, task_thread_info(task));
187 debug_mutex_set_owner(lock, task_thread_info(task)); 187 debug_mutex_set_owner(lock, task_thread_info(task));